diff options
Diffstat (limited to 'engine/lib/views.php')
| -rw-r--r-- | engine/lib/views.php | 1669 |
1 files changed, 959 insertions, 710 deletions
diff --git a/engine/lib/views.php b/engine/lib/views.php index 09653e11d..1142461fe 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -40,7 +40,7 @@ * are called, so the init order doesn't affect views. * * @internal The file that determines the output of the view is the last - * registered by {@link set_view_location()}. + * registered by {@link elgg_set_view_location()}. * * @package Elgg.Core * @subpackage Views @@ -53,6 +53,7 @@ * @global string $CURRENT_SYSTEM_VIEWTYPE * @see elgg_set_viewtype() */ +global $CURRENT_SYSTEM_VIEWTYPE; $CURRENT_SYSTEM_VIEWTYPE = ""; /** @@ -100,12 +101,15 @@ function elgg_get_viewtype() { return $CURRENT_SYSTEM_VIEWTYPE; } - $viewtype = get_input('view', NULL); - if ($viewtype) { - return $viewtype; + $viewtype = get_input('view', '', false); + if (is_string($viewtype) && $viewtype !== '') { + // only word characters allowed. + if (!preg_match('/\W/', $viewtype)) { + return $viewtype; + } } - if (isset($CONFIG->view) && !empty($CONFIG->view)) { + if (!empty($CONFIG->view)) { return $CONFIG->view; } @@ -113,6 +117,45 @@ function elgg_get_viewtype() { } /** + * Register a view type as valid. + * + * @param string $view_type The view type to register + * @return bool + */ +function elgg_register_viewtype($view_type) { + global $CONFIG; + + if (!isset($CONFIG->view_types) || !is_array($CONFIG->view_types)) { + $CONFIG->view_types = array(); + } + + if (!in_array($view_type, $CONFIG->view_types)) { + $CONFIG->view_types[] = $view_type; + } + + return true; +} + +/** + * Checks if $view_type is valid on this installation. + * + * @param string $view_type View type + * + * @return bool + * @since 1.7.2 + * @access private + */ +function elgg_is_valid_view_type($view_type) { + global $CONFIG; + + if (!isset($CONFIG->view_types) || !is_array($CONFIG->view_types)) { + return FALSE; + } + + return in_array($view_type, $CONFIG->view_types); +} + +/** * Register a viewtype to fall back to a default view if a view isn't * found for that viewtype. * @@ -156,6 +199,37 @@ function elgg_does_viewtype_fallback($viewtype) { return FALSE; } +/** + * Register a view to be available for ajax calls + * + * @param string $view The view name + * @return void + * @since 1.8.3 + */ +function elgg_register_ajax_view($view) { + global $CONFIG; + + if (!isset($CONFIG->allowed_ajax_views)) { + $CONFIG->allowed_ajax_views = array(); + } + + $CONFIG->allowed_ajax_views[$view] = true; +} + +/** + * Unregister a view for ajax calls + * + * @param string $view The view name + * @return void + * @since 1.8.3 + */ +function elgg_unregister_ajax_view($view) { + global $CONFIG; + + if (isset($CONFIG->allowed_ajax_views[$view])) { + unset($CONFIG->allowed_ajax_views[$view]); + } +} /** * Returns the file location for a view. @@ -184,6 +258,94 @@ function elgg_get_view_location($view, $viewtype = '') { } else { return $CONFIG->views->locations[$viewtype][$view]; } +} + +/** + * Set an alternative base location for a view. + * + * Views are expected to be in plugin_name/views/. This function can + * be used to change that location. + * + * @internal Core view locations are stored in $CONFIG->viewpath. + * + * @tip This is useful to optionally register views in a plugin. + * + * @param string $view The name of the view + * @param string $location The base location path + * @param string $viewtype The view type + * + * @return void + */ +function elgg_set_view_location($view, $location, $viewtype = '') { + global $CONFIG; + + if (empty($viewtype)) { + $viewtype = 'default'; + } + + if (!isset($CONFIG->views)) { + $CONFIG->views = new stdClass; + } + + if (!isset($CONFIG->views->locations)) { + $CONFIG->views->locations = array($viewtype => array($view => $location)); + + } else if (!isset($CONFIG->views->locations[$viewtype])) { + $CONFIG->views->locations[$viewtype] = array($view => $location); + + } else { + $CONFIG->views->locations[$viewtype][$view] = $location; + } +} + +/** + * Returns whether the specified view exists + * + * @note If $recurse is true, also checks if a view exists only as an extension. + * + * @param string $view The view name + * @param string $viewtype If set, forces the viewtype + * @param bool $recurse If false, do not check extensions + * + * @return bool + */ +function elgg_view_exists($view, $viewtype = '', $recurse = true) { + global $CONFIG; + + // Detect view type + if (empty($viewtype)) { + $viewtype = elgg_get_viewtype(); + } + + if (!isset($CONFIG->views->locations[$viewtype][$view])) { + if (!isset($CONFIG->viewpath)) { + $location = dirname(dirname(dirname(__FILE__))) . "/views/"; + } else { + $location = $CONFIG->viewpath; + } + } else { + $location = $CONFIG->views->locations[$viewtype][$view]; + } + + if (file_exists("{$location}{$viewtype}/{$view}.php")) { + return true; + } + + // If we got here then check whether this exists as an extension + // We optionally recursively check whether the extended view exists also for the viewtype + if ($recurse && isset($CONFIG->views->extensions[$view])) { + foreach ($CONFIG->views->extensions[$view] as $view_extension) { + // do not recursively check to stay away from infinite loops + if (elgg_view_exists($view_extension, $viewtype, false)) { + return true; + } + } + } + + // Now check if the default view exists if the view is registered as a fallback + if ($viewtype != 'default' && elgg_does_viewtype_fallback($viewtype)) { + return elgg_view_exists($view, 'default'); + } return false; } @@ -194,11 +356,12 @@ function elgg_get_view_location($view, $viewtype = '') { * Views are rendered by a template handler and returned as strings. * * Views are called with a special $vars variable set, - * which includes any variables passed as the second parameter, - * as well as some defaults: - * - All $_SESSION vars merged to $vars array. - * - $vars['config'] The $CONFIG global. (Use {@link get_config()} instead). - * - $vars['url'] The site URL. + * which includes any variables passed as the second parameter. + * For backward compatbility, the following variables are also set but we + * recommend that you do not use them: + * - $vars['config'] The $CONFIG global. (Use {@link elgg_get_config()} instead). + * - $vars['url'] The site URL. (use {@link elgg_get_site_url()} instead). + * - $vars['user'] The logged in user. (use {@link elgg_get_logged_in_user_entity()} instead). * * Custom template handlers can be set with {@link set_template_handler()}. * @@ -206,14 +369,14 @@ function elgg_get_view_location($view, $viewtype = '') { * view, $view_name plugin hook. * * @warning Any variables in $_SESSION will override passed vars - * upon name collision. See {@trac #2124}. + * upon name collision. See https://github.com/Elgg/Elgg/issues/2124 * * @param string $view The name and location of the view to use * @param array $vars Variables to pass to the view. * @param boolean $bypass If set to true, elgg_view will bypass any specified * alternative template handler; by default, it will * hand off to this if requested (see set_template_handler) - * @param boolean $debug If set to true, the viewer will complain if it can't find a view + * @param boolean $ignored This argument is ignored and will be removed eventually * @param string $viewtype If set, forces the viewtype for the elgg_view call to be * this value (default: standard detection) * @@ -221,69 +384,94 @@ function elgg_get_view_location($view, $viewtype = '') { * @see set_template_handler() * @example views/elgg_view.php * @link http://docs.elgg.org/View - * @todo $debug isn't used. - * @todo $usercache is redundant. */ -function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $viewtype = '') { +function elgg_view($view, $vars = array(), $bypass = false, $ignored = false, $viewtype = '') { global $CONFIG; - static $usercache; - - $view = (string)$view; + if (!is_string($view) || !is_string($viewtype)) { + elgg_log("View and Viewtype in views must be a strings: $view", 'NOTICE'); + return ''; + } // basic checking for bad paths if (strpos($view, '..') !== false) { - return false; + return ''; + } + + if (!is_array($vars)) { + elgg_log("Vars in views must be an array: $view", 'ERROR'); + $vars = array(); + } + + // Get the current viewtype + if ($viewtype === '') { + $viewtype = elgg_get_viewtype(); + } elseif (preg_match('/\W/', $viewtype)) { + // Viewtypes can only be alphanumeric + return ''; } $view_orig = $view; // Trigger the pagesetup event - if (!isset($CONFIG->pagesetupdone)) { - elgg_trigger_event('pagesetup', 'system'); + if (!isset($CONFIG->pagesetupdone) && $CONFIG->boot_complete) { $CONFIG->pagesetupdone = true; + elgg_trigger_event('pagesetup', 'system'); } - if (!is_array($usercache)) { - $usercache = array(); + // @warning - plugin authors: do not expect user, config, and url to be + // set by elgg_view() in the future. Instead, use elgg_get_logged_in_user_entity(), + // elgg_get_config(), and elgg_get_site_url() in your views. + if (!isset($vars['user'])) { + $vars['user'] = elgg_get_logged_in_user_entity(); } - - if (!is_array($vars)) { - elgg_log('Vars in views must be an array!', 'ERROR'); - $vars = array(); + if (!isset($vars['config'])) { + $vars['config'] = $CONFIG; } - - if (empty($vars)) { - $vars = array(); + if (!isset($vars['url'])) { + $vars['url'] = elgg_get_site_url(); } - $vars['user'] = get_loggedin_user(); - - $vars['config'] = array(); + // full_view is the new preferred key for full view on entities @see elgg_view_entity() + // check if full_view is set because that means we've already rewritten it and this is + // coming from another view passing $vars directly. + if (isset($vars['full']) && !isset($vars['full_view'])) { + elgg_deprecated_notice("Use \$vars['full_view'] instead of \$vars['full']", 1.8, 2); + $vars['full_view'] = $vars['full']; + } + if (isset($vars['full_view'])) { + $vars['full'] = $vars['full_view']; + } - if (!empty($CONFIG)) { - $vars['config'] = $CONFIG; + // internalname => name (1.8) + if (isset($vars['internalname']) && !isset($vars['__ignoreInternalname']) && !isset($vars['name'])) { + elgg_deprecated_notice('You should pass $vars[\'name\'] now instead of $vars[\'internalname\']', 1.8, 2); + $vars['name'] = $vars['internalname']; + } elseif (isset($vars['name'])) { + if (!isset($vars['internalname'])) { + $vars['__ignoreInternalname'] = ''; + } + $vars['internalname'] = $vars['name']; } - $vars['url'] = elgg_get_site_url(); + // internalid => id (1.8) + if (isset($vars['internalid']) && !isset($vars['__ignoreInternalid']) && !isset($vars['name'])) { + elgg_deprecated_notice('You should pass $vars[\'id\'] now instead of $vars[\'internalid\']', 1.8, 2); + $vars['id'] = $vars['internalid']; + } elseif (isset($vars['id'])) { + if (!isset($vars['internalid'])) { + $vars['__ignoreInternalid'] = ''; + } + $vars['internalid'] = $vars['id']; + } // If it's been requested, pass off to a template handler instead if ($bypass == false && isset($CONFIG->template_handler) && !empty($CONFIG->template_handler)) { $template_handler = $CONFIG->template_handler; if (is_callable($template_handler)) { - return $template_handler($view, $vars); + return call_user_func($template_handler, $view, $vars); } } - // Get the current viewtype - if (empty($viewtype)) { - $viewtype = elgg_get_viewtype(); - } - - // Viewtypes can only be alphanumeric - if (preg_match('[\W]', $viewtype)) { - return ''; - } - // Set up any extensions to the requested view if (isset($CONFIG->views->extensions[$view])) { $viewlist = $CONFIG->views->extensions[$view]; @@ -295,19 +483,21 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie ob_start(); foreach ($viewlist as $priority => $view) { + $view_location = elgg_get_view_location($view, $viewtype); $view_file = "$view_location$viewtype/$view.php"; - $default_location = elgg_get_view_location($view, 'default'); - $default_view_file = "{$default_location}default/$view.php"; - // try to include view if (!file_exists($view_file) || !include($view_file)) { // requested view does not exist $error = "$viewtype/$view view does not exist."; // attempt to load default view - if ($viewtype != 'default' && elgg_does_viewtype_fallback($viewtype)) { + if ($viewtype !== 'default' && elgg_does_viewtype_fallback($viewtype)) { + + $default_location = elgg_get_view_location($view, 'default'); + $default_view_file = "{$default_location}default/$view.php"; + if (file_exists($default_view_file) && include($default_view_file)) { // default view found $error .= " Using default/$view instead."; @@ -332,7 +522,7 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie // backward compatibility with less granular hook will be gone in 2.0 $content_tmp = elgg_trigger_plugin_hook('display', 'view', $params, $content); - if ($content_tmp != $content) { + if ($content_tmp !== $content) { $content = $content_tmp; elgg_deprecated_notice('The display:view plugin hook is deprecated by view:view_name', 1.8); } @@ -341,357 +531,253 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie } /** - * Returns whether the specified view exists + * Extends a view with another view. * - * @note If $recurse is strue, also checks if a view exists only as an extension. + * The output of any view can be prepended or appended to any other view. * - * @param string $view The view name - * @param string $viewtype If set, forces the viewtype - * @param bool $recurse If false, do not check extensions + * The default action is to append a view. If the priority is less than 500, + * the output of the extended view will be appended to the original view. * - * @return bool + * Priority can be specified and affects the order in which extensions + * are appended or prepended. + * + * @internal View extensions are stored in + * $CONFIG->views->extensions[$view][$priority] = $view_extension + * + * @param string $view The view to extend. + * @param string $view_extension This view is added to $view + * @param int $priority The priority, from 0 to 1000, + * to add at (lowest numbers displayed first) + * + * @return void + * @since 1.7.0 + * @link http://docs.elgg.org/Views/Extend + * @example views/extend.php */ -function elgg_view_exists($view, $viewtype = '', $recurse = true) { +function elgg_extend_view($view, $view_extension, $priority = 501) { global $CONFIG; - // Detect view type - if (empty($viewtype)) { - $viewtype = elgg_get_viewtype(); - } - - if (!isset($CONFIG->views->locations[$viewtype][$view])) { - if (!isset($CONFIG->viewpath)) { - $location = dirname(dirname(dirname(__FILE__))) . "/views/"; - } else { - $location = $CONFIG->viewpath; - } + if (!isset($CONFIG->views)) { + $CONFIG->views = (object) array( + 'extensions' => array(), + ); + $CONFIG->views->extensions[$view][500] = (string)$view; } else { - $location = $CONFIG->views->locations[$viewtype][$view]; - } - - if (file_exists($location . "{$viewtype}/{$view}.php")) { - return true; + if (!isset($CONFIG->views->extensions[$view])) { + $CONFIG->views->extensions[$view][500] = (string)$view; + } } - // If we got here then check whether this exists as an extension - // We optionally recursively check whether the extended view exists also for the viewtype - if ($recurse && isset($CONFIG->views->extensions[$view])) { - foreach ($CONFIG->views->extensions[$view] as $view_extension) { - // do not recursively check to stay away from infinite loops - if (elgg_view_exists($view_extension, $viewtype, false)) { - return true; - } - } + // raise priority until it doesn't match one already registered + while (isset($CONFIG->views->extensions[$view][$priority])) { + $priority++; } - return false; + $CONFIG->views->extensions[$view][$priority] = (string)$view_extension; + ksort($CONFIG->views->extensions[$view]); } /** - * Registers a view to simple cache. - * - * Simple cache is a caching mechanism that saves the output of - * views and its extensions into a file. If the view is called - * by the {@link simplecache/view.php} file, the Elgg framework will - * not be loaded and the contents of the view will returned - * from file. - * - * @warning Simple cached views must take no parameters and return - * the same content no matter who is logged in. - * - * @note CSS and the basic JS views are cached by the engine. + * Unextends a view. * - * @param string $viewname View name + * @param string $view The view that was extended. + * @param string $view_extension This view that was added to $view * - * @return void - * @link http://docs.elgg.org/Views/Simplecache - * @see elgg_view_regenerate_simplecache() + * @return bool + * @since 1.7.2 */ -function elgg_view_register_simplecache($viewname) { +function elgg_unextend_view($view, $view_extension) { global $CONFIG; - if (!isset($CONFIG->views)) { - $CONFIG->views = new stdClass; + if (!isset($CONFIG->views->extensions[$view])) { + return FALSE; } - if (!isset($CONFIG->views->simplecache)) { - $CONFIG->views->simplecache = array(); + $priority = array_search($view_extension, $CONFIG->views->extensions[$view]); + if ($priority === FALSE) { + return FALSE; } - $CONFIG->views->simplecache[] = $viewname; -} + unset($CONFIG->views->extensions[$view][$priority]); -/** - * Get the URL for the cached file - * - * @param string $type The file type: css or js - * @param string $view The view name - * @return string - * @since 1.8.0 - */ -function elgg_view_get_simplecache_url($type, $view) { - global $CONFIG; - $lastcache = (int)$CONFIG->lastcache; - - if (elgg_view_is_simplecache_enabled()) { - $viewtype = elgg_get_viewtype(); - $url = elgg_get_site_url() . "cache/$type/$view/$viewtype/$view.$lastcache.$type"; - } else { - $url = elgg_get_site_url() . "pg/$type/$view.$lastcache.$type"; - } - return $url; + return TRUE; } /** - * Regenerates the simple cache. + * Assembles and outputs a full page. * - * @warning This does not invalidate the cache, but actively resets it. + * A "page" in Elgg is determined by the current view type and + * can be HTML for a browser, RSS for a feed reader, or + * Javascript, PHP and a number of other formats. * - * @param string $viewtype Optional viewtype to regenerate + * @param string $title Title + * @param string $body Body + * @param string $page_shell Optional page shell to use. See page/shells view directory + * @param array $vars Optional vars array to pass to the page + * shell. Automatically adds title, body, and sysmessages * - * @return void - * @see elgg_view_register_simplecache() + * @return string The contents of the page + * @since 1.8 */ -function elgg_view_regenerate_simplecache($viewtype = NULL) { - global $CONFIG; +function elgg_view_page($title, $body, $page_shell = 'default', $vars = array()) { - if (!isset($CONFIG->views->simplecache) || !is_array($CONFIG->views->simplecache)) { - return; + $messages = null; + if (count_messages()) { + // get messages - try for errors first + $messages = system_messages(NULL, "error"); + if (count($messages["error"]) == 0) { + // no errors so grab rest of messages + $messages = system_messages(null, ""); + } else { + // we have errors - clear out remaining messages + system_messages(null, ""); + } } - $lastcached = time(); - - // @todo elgg_view() checks if the page set is done (isset($CONFIG->pagesetupdone)) and - // triggers an event if it's not. Calling elgg_view() here breaks submenus - // (at least) because the page setup hook is called before any - // contexts can be correctly set (since this is called before page_handler()). - // To avoid this, lie about $CONFIG->pagehandlerdone to force - // the trigger correctly when the first view is actually being output. - $CONFIG->pagesetupdone = TRUE; - - if (!file_exists($CONFIG->dataroot . 'views_simplecache')) { - mkdir($CONFIG->dataroot . 'views_simplecache'); - } + $vars['title'] = $title; + $vars['body'] = $body; + $vars['sysmessages'] = $messages; - if (isset($viewtype)) { - $viewtypes = array($viewtype); + $vars = elgg_trigger_plugin_hook('output:before', 'page', null, $vars); + + // check for deprecated view + if ($page_shell == 'default' && elgg_view_exists('pageshells/pageshell')) { + elgg_deprecated_notice("pageshells/pageshell is deprecated by page/$page_shell", 1.8); + $output = elgg_view('pageshells/pageshell', $vars); } else { - $viewtypes = $CONFIG->view_types; - } - - $original_viewtype = elgg_get_viewtype(); - - foreach ($viewtypes as $viewtype) { - elgg_set_viewtype($viewtype); - foreach ($CONFIG->views->simplecache as $view) { - $viewcontents = elgg_view($view); - $viewname = md5(elgg_get_viewtype() . $view); - if ($handle = fopen($CONFIG->dataroot . 'views_simplecache/' . $viewname, 'w')) { - fwrite($handle, $viewcontents); - fclose($handle); - } - } - - datalist_set("simplecache_lastupdate_$viewtype", $lastcached); - datalist_set("simplecache_lastcached_$viewtype", $lastcached); + $output = elgg_view("page/$page_shell", $vars); } - elgg_set_viewtype($original_viewtype); - - // needs to be set for links in html head - $CONFIG->lastcache = $lastcached; - - unset($CONFIG->pagesetupdone); -} - -/** - * Is simple cache enabled - * - * @return bool - * @since 1.8.0 - */ -function elgg_view_is_simplecache_enabled() { - global $CONFIG; - - if ($CONFIG->simplecache_enabled) { - return true; - } + $vars['page_shell'] = $page_shell; - return false; + // Allow plugins to mod output + return elgg_trigger_plugin_hook('output', 'page', $vars, $output); } /** - * Enables the simple cache. + * Displays a layout with optional parameters. * - * @access private - * @see elgg_view_register_simplecache() - * @return void - */ -function elgg_view_enable_simplecache() { - global $CONFIG; - - datalist_set('simplecache_enabled', 1); - $CONFIG->simplecache_enabled = 1; - elgg_view_regenerate_simplecache(); -} - -/** - * Disables the simple cache. + * Layouts provide consistent organization of pages and other blocks of content. + * There are a few default layouts in core: + * - admin A special layout for the admin area. + * - one_column A single content column. + * - one_sidebar A content column with sidebar. + * - two_sidebar A content column with two sidebars. + * - widgets A widget canvas. * - * @warning Simplecache is also purged when disabled. + * The layout views take the form page/layouts/$layout_name + * See the individual layouts for what options are supported. The three most + * common layouts have these parameters: + * one_column + * content => string + * one_sidebar + * content => string + * sidebar => string (optional) + * content + * content => string + * sidebar => string (optional) + * buttons => string (override the default add button) + * title => string (override the default title) + * filter_context => string (selected content filter) + * See the content layout view for more parameters * - * @access private - * @see elgg_view_register_simplecache() - * @return void - */ -function elgg_view_disable_simplecache() { - global $CONFIG; - if ($CONFIG->simplecache_enabled) { - datalist_set('simplecache_enabled', 0); - $CONFIG->simplecache_enabled = 0; - - // purge simple cache - if ($handle = opendir($CONFIG->dataroot . 'views_simplecache')) { - while (false !== ($file = readdir($handle))) { - if ($file != "." && $file != "..") { - unlink($CONFIG->dataroot . 'views_simplecache/' . $file); - } - } - closedir($handle); - } - } -} - -/** - * Invalidates all cached views in the simplecache + * @param string $layout_name The name of the view in page/layouts/. + * @param array $vars Associative array of parameters for the layout view * - * @return bool - * @since 1.7.4 + * @return string The layout */ -function elgg_invalidate_simplecache() { - global $CONFIG; - - $return = TRUE; +function elgg_view_layout($layout_name, $vars = array()) { - if ($handle = opendir($CONFIG->dataroot . 'views_simplecache')) { - while (false !== ($file = readdir($handle))) { - if ($file != "." && $file != "..") { - $return = $return && unlink($CONFIG->dataroot . 'views_simplecache/' . $file); - } + if (is_string($vars) || $vars === null) { + elgg_deprecated_notice("The use of unlimited optional string arguments in elgg_view_layout() was deprecated in favor of an options array", 1.8); + $arg = 1; + $param_array = array(); + while ($arg < func_num_args()) { + $param_array['area' . $arg] = func_get_arg($arg); + $arg++; } - closedir($handle); } else { - $return = FALSE; + $param_array = $vars; } - return $return; -} + $params = elgg_trigger_plugin_hook('output:before', 'layout', null, $param_array); -/** - * Returns the name of views for in a directory. - * - * Use this to get all namespaced views under the first element. - * - * @param string $dir The main directory that holds the views. (mod/profile/views/) - * @param string $base The root name of the view to use, without the viewtype. (profile) - * - * @return array - * @since 1.7.0 - * @todo Why isn't this used anywhere else but in elgg_view_tree()? - * Seems like a useful function for autodiscovery. - */ -function elgg_get_views($dir, $base) { - $return = array(); - if (file_exists($dir) && is_dir($dir)) { - if ($handle = opendir($dir)) { - while ($view = readdir($handle)) { - if (!in_array($view, array('.', '..', '.svn', 'CVS'))) { - if (is_dir($dir . '/' . $view)) { - if ($val = elgg_get_views($dir . '/' . $view, $base . '/' . $view)) { - $return = array_merge($return, $val); - } - } else { - $view = str_replace('.php', '', $view); - $return[] = $base . '/' . $view; - } - } - } - } + // check deprecated location + if (elgg_view_exists("canvas/layouts/$layout_name")) { + elgg_deprecated_notice("canvas/layouts/$layout_name is deprecated by page/layouts/$layout_name", 1.8); + $output = elgg_view("canvas/layouts/$layout_name", $params); + } elseif (elgg_view_exists("page/layouts/$layout_name")) { + $output = elgg_view("page/layouts/$layout_name", $params); + } else { + $output = elgg_view("page/layouts/default", $params); } - return $return; -} - -/** - * Get views in a dir - * - * @deprecated 1.7. Use elgg_get_views(). - * - * @param string $dir Dir - * @param string $base Base view - * - * @return array - */ -function get_views($dir, $base) { - elgg_deprecated_notice('get_views() was deprecated by elgg_get_views()!', 1.7); - elgg_get_views($dir, $base); + return elgg_trigger_plugin_hook('output:after', 'layout', $params, $output); } /** - * Returns all views below a partial view. + * Render a menu + * + * @see elgg_register_menu_item() for documentation on adding menu items and + * navigation.php for information on the different menus available. + * + * This function triggers a 'register', 'menu:<menu name>' plugin hook that enables + * plugins to add menu items just before a menu is rendered. This is used by + * dynamic menus (menus that change based on some input such as the user hover + * menu). Using elgg_register_menu_item() in response to the hook can cause + * incorrect links to show up. See the blog plugin's blog_owner_block_menu() + * for an example of using this plugin hook. + * + * An additional hook is the 'prepare', 'menu:<menu name>' which enables plugins + * to modify the structure of the menu (sort it, remove items, set variables on + * the menu items). + * + * elgg_view_menu() uses views in navigation/menu + * + * @param string $menu_name The name of the menu + * @param array $vars An associative array of display options for the menu. + * Options include: + * sort_by => string or php callback + * string options: 'name', 'priority', 'title' (default), + * 'register' (registration order) or a + * php callback (a compare function for usort) + * handler: string the page handler to build action URLs + * entity: ElggEntity to use to build action URLs + * class: string the class for the entire menu. + * show_section_headers: bool show headers before menu sections. * - * Settings $view_root = 'profile' will show all available views under - * the "profile" namespace. - * - * @param string $view_root The root view - * @param string $viewtype Optionally specify a view type - * other than the current one. - * - * @return array A list of view names underneath that root view - * @todo This is used once in the deprecated get_activity_stream_data() function. + * @return string + * @since 1.8.0 */ -function elgg_view_tree($view_root, $viewtype = "") { +function elgg_view_menu($menu_name, array $vars = array()) { global $CONFIG; - static $treecache; - // Get viewtype - if (!$viewtype) { - $viewtype = elgg_get_viewtype(); - } + $vars['name'] = $menu_name; - // Has the treecache been initialised? - if (!isset($treecache)) { - $treecache = array(); - } - // A little light internal caching - if (!empty($treecache[$view_root])) { - return $treecache[$view_root]; - } + $sort_by = elgg_extract('sort_by', $vars, 'text'); - // Examine $CONFIG->views->locations - if (isset($CONFIG->views->locations[$viewtype])) { - foreach ($CONFIG->views->locations[$viewtype] as $view => $path) { - $pos = strpos($view, $view_root); - if ($pos === 0) { - $treecache[$view_root][] = $view; - } - } + if (isset($CONFIG->menus[$menu_name])) { + $menu = $CONFIG->menus[$menu_name]; + } else { + $menu = array(); } - // Now examine core - $location = $CONFIG->viewpath; - $viewtype = elgg_get_viewtype(); - $root = $location . $viewtype . '/' . $view_root; + // Give plugins a chance to add menu items just before creation. + // This supports dynamic menus (example: user_hover). + $menu = elgg_trigger_plugin_hook('register', "menu:$menu_name", $vars, $menu); - if (file_exists($root) && is_dir($root)) { - $val = elgg_get_views($root, $view_root); - if (!is_array($treecache[$view_root])) { - $treecache[$view_root] = array(); - } - $treecache[$view_root] = array_merge($treecache[$view_root], $val); - } + $builder = new ElggMenuBuilder($menu); + $vars['menu'] = $builder->getMenu($sort_by); + $vars['selected_item'] = $builder->getSelected(); - return $treecache[$view_root]; + // Let plugins modify the menu + $vars['menu'] = elgg_trigger_plugin_hook('prepare', "menu:$menu_name", $vars, $vars['menu']); + + if (elgg_view_exists("navigation/menu/$menu_name")) { + return elgg_view("navigation/menu/$menu_name", $vars); + } else { + return elgg_view("navigation/menu/default", $vars); + } } /** @@ -704,14 +790,17 @@ function elgg_view_tree($view_root, $viewtype = "") { * * The entity view is called with the following in $vars: * - ElggEntity 'entity' The entity being viewed - * - bool 'full' Whether to show a full or condensed view. + * + * Other common view $vars paramters: + * - bool 'full_view' Whether to show a full or condensed view. * * @tip This function can automatically appends annotations to entities if in full - * view and a handler is registered for the entity:annotate. See {@trac 964} and + * view and a handler is registered for the entity:annotate. See https://github.com/Elgg/Elgg/issues/964 and * {@link elgg_view_entity_annotations()}. * * @param ElggEntity $entity The entity to display - * @param boolean $full Passed to entity view to decide how much information to show. + * @param array $vars Array of variables to pass to the entity view. + * In Elgg 1.7 and earlier it was the boolean $full_view * @param boolean $bypass If false, will not pass to a custom template handler. * {@see set_template_handler()} * @param boolean $debug Complain if views are missing @@ -721,26 +810,36 @@ function elgg_view_tree($view_root, $viewtype = "") { * @link http://docs.elgg.org/Entities * @todo The annotation hook might be better as a generic plugin hook to append content. */ -function elgg_view_entity(ElggEntity $entity, $full = false, $bypass = true, $debug = false) { - global $autofeed; - $autofeed = true; +function elgg_view_entity(ElggEntity $entity, $vars = array(), $bypass = true, $debug = false) { // No point continuing if entity is null - if (!$entity) { - return ''; + if (!$entity || !($entity instanceof ElggEntity)) { + return false; } - if (!($entity instanceof ElggEntity)) { - return false; + global $autofeed; + $autofeed = true; + + $defaults = array( + 'full_view' => false, + ); + + if (is_array($vars)) { + $vars = array_merge($defaults, $vars); + } else { + elgg_deprecated_notice("Update your use of elgg_view_entity()", 1.8); + $vars = array( + 'full_view' => $vars, + ); } + $vars['entity'] = $entity; + + // if this entity has a view defined, use it $view = $entity->view; if (is_string($view)) { - return elgg_view($view, - array('entity' => $entity, 'full' => $full), - $bypass, - $debug); + return elgg_view($view, $vars, $bypass, $debug); } $entity_type = $entity->getType(); @@ -751,21 +850,16 @@ function elgg_view_entity(ElggEntity $entity, $full = false, $bypass = true, $de } $contents = ''; - if (elgg_view_exists("{$entity_type}/{$subtype}")) { - $contents = elgg_view("{$entity_type}/{$subtype}", array( - 'entity' => $entity, - 'full' => $full - ), $bypass, $debug); + if (elgg_view_exists("$entity_type/$subtype")) { + $contents = elgg_view("$entity_type/$subtype", $vars, $bypass, $debug); } if (empty($contents)) { - $contents = elgg_view("{$entity_type}/default", array( - 'entity' => $entity, - 'full' => $full - ), $bypass, $debug); + $contents = elgg_view("$entity_type/default", $vars, $bypass, $debug); } + // Marcus Povey 20090616 : Speculative and low impact approach for fixing #964 - if ($full) { - $annotations = elgg_view_entity_annotations($entity, $full); + if ($vars['full_view']) { + $annotations = elgg_view_entity_annotations($entity, $vars['full_view']); if ($annotations) { $contents .= $annotations; @@ -775,6 +869,52 @@ function elgg_view_entity(ElggEntity $entity, $full = false, $bypass = true, $de } /** + * View the icon of an entity + * + * Entity views are determined by having a view named after the entity $type/$subtype. + * Entities that do not have a defined icon/$type/$subtype view will fall back to using + * the icon/$type/default view. + * + * @param ElggEntity $entity The entity to display + * @param string $size The size: tiny, small, medium, large + * @param array $vars An array of variables to pass to the view. Some possible + * variables are img_class and link_class. See the + * specific icon view for more parameters. + * + * @return string HTML to display or false + */ +function elgg_view_entity_icon(ElggEntity $entity, $size = 'medium', $vars = array()) { + + // No point continuing if entity is null + if (!$entity || !($entity instanceof ElggEntity)) { + return false; + } + + $vars['entity'] = $entity; + $vars['size'] = $size; + + $entity_type = $entity->getType(); + + $subtype = $entity->getSubtype(); + if (empty($subtype)) { + $subtype = 'default'; + } + + $contents = ''; + if (elgg_view_exists("icon/$entity_type/$subtype")) { + $contents = elgg_view("icon/$entity_type/$subtype", $vars); + } + if (empty($contents)) { + $contents = elgg_view("icon/$entity_type/default", $vars); + } + if (empty($contents)) { + $contents = elgg_view("icon/default", $vars); + } + + return $contents; +} + +/** * Returns a string of a rendered annotation. * * Annotation views are expected to be in annotation/$annotation_name. @@ -787,38 +927,43 @@ function elgg_view_entity(ElggEntity $entity, $full = false, $bypass = true, $de * - ElggEntity 'annotation' The annotation being viewed. * * @param ElggAnnotation $annotation The annotation to display - * @param boolean $bypass If false, will not pass to a custom + * @param array $vars Variable array for view. + * @param bool $bypass If false, will not pass to a custom * template handler. {@see set_template_handler()} - * @param boolean $debug Complain if views are missing + * @param bool $debug Complain if views are missing * - * @return string HTML (etc) to display + * @return string/false Rendered annotation */ -function elgg_view_annotation(ElggAnnotation $annotation, $bypass = true, $debug = false) { +function elgg_view_annotation(ElggAnnotation $annotation, array $vars = array(), $bypass = true, $debug = false) { global $autofeed; $autofeed = true; + $defaults = array( + 'full_view' => true, + ); + + $vars = array_merge($defaults, $vars); + $vars['annotation'] = $annotation; + + // @todo setting the view on an annotation is not advertised anywhere + // do we want to keep this? $view = $annotation->view; if (is_string($view)) { - return elgg_view($view, array('annotation' => $annotation), $bypass, $debug); + return elgg_view($view, $vars, $bypass, $debug); } $name = $annotation->name; - $intname = (int) $name; - if ("{$intname}" == "{$name}") { - $name = get_metastring($intname); - } if (empty($name)) { - return ""; + return false; } - if (elgg_view_exists("annotation/{$name}")) { - return elgg_view("annotation/{$name}", array('annotation' => $annotation), $bypass, $debug); + if (elgg_view_exists("annotation/$name")) { + return elgg_view("annotation/$name", $vars, $bypass, $debug); } else { - return elgg_view("annotation/default", array('annotation' => $annotation), $bypass, $debug); + return elgg_view("annotation/default", $vars, $bypass, $debug); } } - /** * Returns a rendered list of entities with pagination. This function should be * called by wrapper functions. @@ -829,87 +974,110 @@ function elgg_view_annotation(ElggAnnotation $annotation, $bypass = true, $debug * @see elgg_list_entities_from_relationships() * @see elgg_list_entities_from_annotations() * - * @param array $entities List of entities - * @param int $count The total number of entities across all pages - * @param int $offset The current indexing offset - * @param int $limit The number of entities to display per page - * @param bool $fullview Whether or not to display the full view (default: true) - * @param bool $listtypetoggle Whether or not to allow users to toggle to gallery view - * @param bool $pagination Whether pagination is offered. - * - * @return string The list of entities + * @param array $entities Array of entities + * @param array $vars Display variables + * 'count' The total number of entities across all pages + * 'offset' The current indexing offset + * 'limit' The number of entities to display per page + * 'full_view' Display the full view of the entities? + * 'list_class' CSS class applied to the list + * 'item_class' CSS class applied to the list items + * 'pagination' Display pagination? + * 'list_type' List type: 'list' (default), 'gallery' + * 'list_type_toggle' Display the list type toggle? + * + * @return string The rendered list of entities * @access private */ -function elgg_view_entity_list($entities, $count, $offset, $limit, $full_view = true, +function elgg_view_entity_list($entities, $vars = array(), $offset = 0, $limit = 10, $full_view = true, $list_type_toggle = true, $pagination = true) { - $count = (int) $count; - $limit = (int) $limit; + if (!$vars["limit"] && !$vars["offset"]) { + // no need for pagination if listing is unlimited
+ $vars["pagination"] = false;
+ }
+ + if (!is_int($offset)) { + $offset = (int)get_input('offset', 0); + } - // do not require views to explicitly pass in the offset - if (!$offset = (int) $offset) { - $offset = sanitise_int(get_input('offset', 0)); + // list type can be passed as request parameter + $list_type = get_input('list_type', 'list'); + if (get_input('listtype')) { + elgg_deprecated_notice("'listtype' has been deprecated by 'list_type' for lists", 1.8); + $list_type = get_input('listtype'); } - $context = elgg_get_context(); + if (is_array($vars)) { + // new function + $defaults = array( + 'items' => $entities, + 'list_class' => 'elgg-list-entity', + 'full_view' => true, + 'pagination' => true, + 'list_type' => $list_type, + 'list_type_toggle' => false, + 'offset' => $offset, + ); - $html = elgg_view('entities/list', array( - 'entities' => $entities, - 'count' => $count, - 'offset' => $offset, - 'limit' => $limit, - 'baseurl' => $_SERVER['REQUEST_URI'], - 'fullview' => $full_view, - 'context' => $context, - 'listtypetoggle' => $list_type_toggle, - 'listtype' => get_input('listtype', 'list'), - 'pagination' => $pagination - )); + $vars = array_merge($defaults, $vars); - return $html; + } else { + // old function parameters + elgg_deprecated_notice("Please update your use of elgg_view_entity_list()", 1.8); + + $vars = array( + 'items' => $entities, + 'count' => (int) $vars, // the old count parameter + 'offset' => $offset, + 'limit' => (int) $limit, + 'full_view' => $full_view, + 'pagination' => $pagination, + 'list_type' => $list_type, + 'list_type_toggle' => $list_type_toggle, + 'list_class' => 'elgg-list-entity', + ); + } + + if ($vars['list_type'] != 'list') { + return elgg_view('page/components/gallery', $vars); + } else { + return elgg_view('page/components/list', $vars); + } } /** * Returns a rendered list of annotations, plus pagination. This function * should be called by wrapper functions. * - * @param array $annotations List of annotations - * @param int $count The total number of annotations across all pages - * @param int $offset The current indexing offset - * @param int $limit The number of annotations to display per page + * @param array $annotations Array of annotations + * @param array $vars Display variables + * 'count' The total number of annotations across all pages + * 'offset' The current indexing offset + * 'limit' The number of annotations to display per page + * 'full_view' Display the full view of the annotation? + * 'list_class' CSS Class applied to the list + * 'offset_key' The url parameter key used for offset * * @return string The list of annotations * @access private */ -function elgg_view_annotation_list($annotations, $count, $offset, $limit) { - $count = (int) $count; - $offset = (int) $offset; - $limit = (int) $limit; - - $html = ""; - - $nav = elgg_view('navigation/pagination', array( - 'baseurl' => $_SERVER['REQUEST_URI'], - 'offset' => $offset, - 'count' => $count, - 'limit' => $limit, - 'word' => 'annoff', - 'nonefound' => false, - )); - - $html .= $nav; - - if (is_array($annotations) && sizeof($annotations) > 0) { - foreach ($annotations as $annotation) { - $html .= elgg_view_annotation($annotation, "", false); - } - } - - if ($count) { - $html .= $nav; +function elgg_view_annotation_list($annotations, array $vars = array()) { + $defaults = array( + 'items' => $annotations, + 'list_class' => 'elgg-list-annotation elgg-annotation-list', // @todo remove elgg-annotation-list in Elgg 1.9 + 'full_view' => true, + 'offset_key' => 'annoff', + ); + + $vars = array_merge($defaults, $vars); + + if (!$vars["limit"] && !$vars["offset"]) {
+ // no need for pagination if listing is unlimited
+ $vars["pagination"] = false;
} - return $html; + return elgg_view('page/components/list', $vars); } /** @@ -920,17 +1088,13 @@ function elgg_view_annotation_list($annotations, $count, $offset, $limit) { * * This is called automatically by the framework from {@link elgg_view_entity()} * - * @param ElggEntity $entity Entity - * @param bool $full Full view? + * @param ElggEntity $entity Entity + * @param bool $full_view Display full view? * * @return mixed string or false on failure * @todo Change the hook name. */ -function elgg_view_entity_annotations(ElggEntity $entity, $full = true) { - if (!$entity) { - return false; - } - +function elgg_view_entity_annotations(ElggEntity $entity, $full_view = true) { if (!($entity instanceof ElggEntity)) { return false; } @@ -940,7 +1104,7 @@ function elgg_view_entity_annotations(ElggEntity $entity, $full = true) { $annotations = elgg_trigger_plugin_hook('entity:annotate', $entity_type, array( 'entity' => $entity, - 'full' => $full, + 'full_view' => $full_view, ) ); @@ -948,64 +1112,24 @@ function elgg_view_entity_annotations(ElggEntity $entity, $full = true) { } /** - * Displays a layout with optional parameters. - * - * Layouts provide consistent organization of pages and other blocks of content. - * There are a few default layouts in core: - * - administration A special layout for the admin area. - * - one_column A single content column. - * - one_column_with_sidebar A content column with sidebar. - * - widgets A widget canvas. + * Renders a title. * - * The layout views take the form canvas/layouts/$layout_name - * See the individual layouts for what options are supported. The two most - * common layouts have these parameters: - * one_column - * content => string - * one_column_with_sidebar - * content => string - * sidebar => string (optional) + * This is a shortcut for {@elgg_view page/elements/title}. * - * @param string $layout The name of the view in canvas/layouts/. - * @param array $vars Associative array of parameters for the layout view + * @param string $title The page title + * @param array $vars View variables (was submenu be displayed? (deprecated)) * - * @return string The layout + * @return string The HTML (etc) */ -function elgg_view_layout($layout_name, $vars = array()) { - - if (is_string($vars)) { - elgg_deprecated_notice("The use of unlimited optional string arguments in elgg_view_layout() was deprecated in favor of an options array", 1.8); - $arg = 1; - $param_array = array(); - while ($arg < func_num_args()) { - $param_array['area' . $arg] = func_get_arg($arg); - $arg++; - } - } else { - $param_array = $vars; - } - - if (elgg_view_exists("layouts/{$layout_name}")) { - return elgg_view("layouts/{$layout_name}", $param_array); - } else { - return elgg_view("layouts/default", $param_array); +function elgg_view_title($title, $vars = array()) { + if (!is_array($vars)) { + elgg_deprecated_notice('setting $submenu in elgg_view_title() is deprecated', 1.8); + $vars = array('submenu' => $vars); } -} -/** - * Returns a rendered title. - * - * This is a shortcut for {@elgg_view page_elements/title}. - * - * @param string $title The page title - * @param string $submenu Should a submenu be displayed? (default false, use not recommended) - * - * @return string The HTML (etc) - */ -function elgg_view_title($title, $submenu = false) { - $title = elgg_view('page_elements/title', array('title' => $title, 'submenu' => $submenu)); + $vars['title'] = $title; - return $title; + return elgg_view('page/elements/title', $vars); } /** @@ -1028,214 +1152,353 @@ function elgg_view_friendly_time($time) { * * @tip Plugins can override the output by registering a handler * for the comments, $entity_type hook. The handler is responsible - * for formatting the comments and add comment form. + * for formatting the comments and the add comment form. * * @param ElggEntity $entity The entity to view comments of - * @param bool $add_comment Include a form to add comments + * @param bool $add_comment Include a form to add comments? + * @param array $vars Variables to pass to comment view * - * @return string|false The HTML (etc) for the comments, or false on failure + * @return string|false Rendered comments or false on failure * @link http://docs.elgg.org/Entities/Comments * @link http://docs.elgg.org/Annotations/Comments */ -function elgg_view_comments($entity, $add_comment = true) { +function elgg_view_comments($entity, $add_comment = true, array $vars = array()) { if (!($entity instanceof ElggEntity)) { return false; } - $comments = elgg_trigger_plugin_hook('comments', $entity->getType(), array('entity' => $entity), false); - if ($comemnts) { - return $comments; - } else { - $comments = list_annotations($entity->getGUID(), 'generic_comment'); - - //display the new comment form if required - if ($add_comment) { - $comments .= elgg_view('comments/forms/edit', array('entity' => $entity)); - } + $vars['entity'] = $entity; + $vars['show_add_form'] = $add_comment; + $vars['class'] = elgg_extract('class', $vars, "{$entity->getSubtype()}-comments"); - return $comments; + $output = elgg_trigger_plugin_hook('comments', $entity->getType(), $vars, false); + if ($output) { + return $output; + } else { + return elgg_view('page/elements/comments', $vars); } } - /** - * Wrapper function to display search listings. + * Wrapper function for the image block display pattern. + * + * Fixed width media on the side (image, icon, flash, etc.). + * Descriptive content filling the rest of the column. * - * @param string $icon The icon for the listing - * @param string $info Any information that needs to be displayed. + * This is a shortcut for {@elgg_view page/components/image_block}. * - * @return string The HTML (etc) representing the listing + * @param string $image The icon and other information + * @param string $body Description content + * @param array $vars Additional parameters for the view + * + * @return string + * @since 1.8.0 */ -function elgg_view_listing($icon, $info) { - return elgg_view('entities/entity_listing', array('icon' => $icon, 'info' => $info)); +function elgg_view_image_block($image, $body, $vars = array()) { + $vars['image'] = $image; + $vars['body'] = $body; + return elgg_view('page/components/image_block', $vars); } /** - * Registers a function to handle templates. + * Wrapper function for the module display pattern. * - * Alternative template handlers can be registered to handle - * all output functions. By default, {@link elgg_view()} will - * simply include the view file. If an alternate template handler - * is registered, the view name and passed $vars will be passed to the - * registered function, which is then responsible for generating and returning - * output. + * Box with header, body, footer * - * Template handlers need to accept two arguments: string $view_name and array - * $vars. + * This is a shortcut for {@elgg_view page/components/module}. * - * @warning This is experimental. + * @param string $type The type of module (main, info, popup, aside, etc.) + * @param string $title A title to put in the header + * @param string $body Content of the module + * @param array $vars Additional parameters for the module * - * @param string $function_name The name of the function to pass to. + * @return string + * @since 1.8.0 + */ +function elgg_view_module($type, $title, $body, array $vars = array()) { + $vars['class'] = elgg_extract('class', $vars, '') . " elgg-module-$type"; + $vars['title'] = $title; + $vars['body'] = $body; + return elgg_view('page/components/module', $vars); +} + +/** + * Renders a human-readable representation of a river item * - * @return bool - * @see elgg_view() - * @link http://docs.elgg.org/Views/TemplateHandlers + * @param ElggRiverItem $item A river item object + * @param array $vars An array of variables for the view + * + * @return string returns empty string if could not be rendered */ -function set_template_handler($function_name) { - global $CONFIG; - if (!empty($function_name) && is_callable($function_name)) { - $CONFIG->template_handler = $function_name; - return true; +function elgg_view_river_item($item, array $vars = array()) { + if (!($item instanceof ElggRiverItem)) { + return ''; } - return false; + // checking default viewtype since some viewtypes do not have unique views per item (rss) + $view = $item->getView(); + if (!$view || !elgg_view_exists($view, 'default')) { + return ''; + } + + $subject = $item->getSubjectEntity(); + $object = $item->getObjectEntity(); + if (!$subject || !$object) { + // subject is disabled or subject/object deleted + return ''; + } + + // @todo this needs to be cleaned up + // Don't hide objects in closed groups that a user can see. + // see https://github.com/elgg/elgg/issues/4789 + // else { + // // hide based on object's container + // $visibility = ElggGroupItemVisibility::factory($object->container_guid); + // if ($visibility->shouldHideItems) { + // return ''; + // } + // } + + $vars['item'] = $item; + + return elgg_view('river/item', $vars); } /** - * Extends a view with another view. + * Convenience function for generating a form from a view in a standard location. * - * The output of any view can be prepended or appended to any other view. + * This function assumes that the body of the form is located at "forms/$action" and + * sets the action by default to "action/$action". Automatically wraps the forms/$action + * view with a <form> tag and inserts the anti-csrf security tokens. * - * The default action is to append a view. If the priority is less than 500, - * the output of the extended view will be appended to the original view. + * @tip This automatically appends elgg-form-action-name to the form's class. It replaces any + * slashes with dashes (blog/save becomes elgg-form-blog-save) * - * Priority can be specified and affects the order in which extensions - * are appended or prepended. + * @example + * <code>echo elgg_view_form('login');</code> * - * @internal View extensions are stored in - * $CONFIG->views->extensions[$view][$priority] = $view_extension + * This would assume a "login" form body to be at "forms/login" and would set the action + * of the form to "http://yoursite.com/action/login". * - * @param string $view The view to extend. - * @param string $view_extension This view is added to $view - * @param int $priority The priority, from 0 to 1000, - * to add at (lowest numbers displayed first) - * @param string $viewtype Not used + * If elgg_view('forms/login') is: + * <input type="text" name="username" /> + * <input type="password" name="password" /> * - * @return void - * @since 1.7.0 - * @link http://docs.elgg.org/Views/Ejxtend - * @example views/extend.php + * Then elgg_view_form('login') generates: + * <form action="http://yoursite.com/action/login" method="post"> + * ...security tokens... + * <input type="text" name="username" /> + * <input type="password" name="password" /> + * </form> + * + * @param string $action The name of the action. An action name does not include + * the leading "action/". For example, "login" is an action name. + * @param array $form_vars $vars environment passed to the "input/form" view + * @param array $body_vars $vars environment passed to the "forms/$action" view + * + * @return string The complete form */ -function elgg_extend_view($view, $view_extension, $priority = 501, $viewtype = '') { +function elgg_view_form($action, $form_vars = array(), $body_vars = array()) { global $CONFIG; - if (!isset($CONFIG->views)) { - $CONFIG->views = new stdClass; - } - - if (!isset($CONFIG->views->extensions)) { - $CONFIG->views->extensions = array(); - } + $defaults = array( + 'action' => $CONFIG->wwwroot . "action/$action", + 'body' => elgg_view("forms/$action", $body_vars) + ); - if (!isset($CONFIG->views->extensions[$view])) { - $CONFIG->views->extensions[$view][500] = "{$view}"; - } + $form_class = 'elgg-form-' . preg_replace('/[^a-z0-9]/i', '-', $action); - while (isset($CONFIG->views->extensions[$view][$priority])) { - $priority++; + // append elgg-form class to any class options set + if (isset($form_vars['class'])) { + $form_vars['class'] = $form_vars['class'] . " $form_class"; + } else { + $form_vars['class'] = $form_class; } - $CONFIG->views->extensions[$view][$priority] = "{$view_extension}"; - ksort($CONFIG->views->extensions[$view]); + return elgg_view('input/form', array_merge($defaults, $form_vars)); } /** - * Unextends a view. + * View an item in a list * - * @param string $view The view that was extended. - * @param string $view_extension This view that was added to $view + * @param ElggEntity|ElggAnnotation $item + * @param array $vars Additional parameters for the rendering * - * @return bool - * @since 1.7.2 + * @return string + * @since 1.8.0 + * @access private */ -function elgg_unextend_view($view, $view_extension) { +function elgg_view_list_item($item, array $vars = array()) { global $CONFIG; - if (!isset($CONFIG->views)) { - return FALSE; + $type = $item->getType(); + if (in_array($type, $CONFIG->entity_types)) { + return elgg_view_entity($item, $vars); + } else if ($type == 'annotation') { + return elgg_view_annotation($item, $vars); + } else if ($type == 'river') { + return elgg_view_river_item($item, $vars); } - if (!isset($CONFIG->views->extensions)) { - return FALSE; - } + return ''; +} - if (!isset($CONFIG->views->extensions[$view])) { - return FALSE; +/** + * View one of the elgg sprite icons + * + * Shorthand for <span class="elgg-icon elgg-icon-$name"></span> + * + * @param string $name The specific icon to display + * @param string $class Additional class: float, float-alt, or custom class + * + * @return string The html for displaying an icon + */ +function elgg_view_icon($name, $class = '') { + // @todo deprecate boolean in Elgg 1.9 + if ($class === true) { + $class = 'float'; } + return "<span class=\"elgg-icon elgg-icon-$name $class\"></span>"; +} - $priority = array_search($view_extension, $CONFIG->views->extensions[$view]); - if ($priority === FALSE) { - return FALSE; +/** + * Displays a user's access collections, using the core/friends/collections view + * + * @param int $owner_guid The GUID of the owning user + * + * @return string A formatted rendition of the collections + * @todo Move to the friends/collection.php page. + * @access private + */ +function elgg_view_access_collections($owner_guid) { + if ($collections = get_user_access_collections($owner_guid)) { + foreach ($collections as $key => $collection) { + $collections[$key]->members = get_members_of_access_collection($collection->id, true); + $collections[$key]->entities = get_user_friends($owner_guid, "", 9999); + } } - unset($CONFIG->views->extensions[$view][$priority]); - - return TRUE; + return elgg_view('core/friends/collections', array('collections' => $collections)); } /** - * Extend a view + * Registers a function to handle templates. * - * @deprecated 1.7. Use elgg_extend_view(). + * Alternative template handlers can be registered to handle + * all output functions. By default, {@link elgg_view()} will + * simply include the view file. If an alternate template handler + * is registered, the view name and passed $vars will be passed to the + * registered function, which is then responsible for generating and returning + * output. * - * @param string $view The view to extend. - * @param string $view_name This view is added to $view - * @param int $priority The priority, from 0 to 1000, - * to add at (lowest numbers displayed first) - * @param string $viewtype Not used + * Template handlers need to accept two arguments: string $view_name and array + * $vars. * - * @return void + * @warning This is experimental. + * + * @param string $function_name The name of the function to pass to. + * + * @return bool + * @see elgg_view() + * @link http://docs.elgg.org/Views/TemplateHandlers */ -function extend_view($view, $view_name, $priority = 501, $viewtype = '') { - elgg_deprecated_notice('extend_view() was deprecated by elgg_extend_view()!', 1.7); - elgg_extend_view($view, $view_name, $priority, $viewtype); +function set_template_handler($function_name) { + global $CONFIG; + + if (is_callable($function_name)) { + $CONFIG->template_handler = $function_name; + return true; + } + return false; } /** - * Set an alternative base location for a view. + * Returns the name of views for in a directory. * - * Views are expected to be in plugin_name/views/. This function can - * be used to change that location. + * Use this to get all namespaced views under the first element. * - * @internal Core view locations are stored in $CONFIG->viewpath. + * @param string $dir The main directory that holds the views. (mod/profile/views/) + * @param string $base The root name of the view to use, without the viewtype. (profile) * - * @tip This is useful to optionally register views in a plugin. + * @return array + * @since 1.7.0 + * @todo Why isn't this used anywhere else but in elgg_view_tree()? + * Seems like a useful function for autodiscovery. + * @access private + */ +function elgg_get_views($dir, $base) { + $return = array(); + if (file_exists($dir) && is_dir($dir)) { + if ($handle = opendir($dir)) { + while ($view = readdir($handle)) { + if (!in_array($view, array('.', '..', '.svn', 'CVS'))) { + if (is_dir($dir . '/' . $view)) { + if ($val = elgg_get_views($dir . '/' . $view, $base . '/' . $view)) { + $return = array_merge($return, $val); + } + } else { + $view = str_replace('.php', '', $view); + $return[] = $base . '/' . $view; + } + } + } + } + } + + return $return; +} + +/** + * Returns all views below a partial view. * - * @param string $view The name of the view - * @param string $location The base location path - * @param string $viewtype The view type + * Settings $view_root = 'profile' will show all available views under + * the "profile" namespace. * - * @return void + * @param string $view_root The root view + * @param string $viewtype Optionally specify a view type + * other than the current one. + * + * @return array A list of view names underneath that root view + * @todo This is used once in the deprecated get_activity_stream_data() function. + * @access private */ -function set_view_location($view, $location, $viewtype = '') { +function elgg_view_tree($view_root, $viewtype = "") { global $CONFIG; + static $treecache = array(); - if (empty($viewtype)) { - $viewtype = 'default'; + // Get viewtype + if (!$viewtype) { + $viewtype = elgg_get_viewtype(); } - if (!isset($CONFIG->views)) { - $CONFIG->views = new stdClass; + // A little light internal caching + if (!empty($treecache[$view_root])) { + return $treecache[$view_root]; } - if (!isset($CONFIG->views->locations)) { - $CONFIG->views->locations = array($viewtype => array($view => $location)); + // Examine $CONFIG->views->locations + if (isset($CONFIG->views->locations[$viewtype])) { + foreach ($CONFIG->views->locations[$viewtype] as $view => $path) { + $pos = strpos($view, $view_root); + if ($pos === 0) { + $treecache[$view_root][] = $view; + } + } + } - } else if (!isset($CONFIG->views->locations[$viewtype])) { - $CONFIG->views->locations[$viewtype] = array($view => $location); + // Now examine core + $location = $CONFIG->viewpath; + $viewtype = elgg_get_viewtype(); + $root = $location . $viewtype . '/' . $view_root; - } else { - $CONFIG->views->locations[$viewtype][$view] = $location; + if (file_exists($root) && is_dir($root)) { + $val = elgg_get_views($root, $view_root); + if (!is_array($treecache[$view_root])) { + $treecache[$view_root] = array(); + } + $treecache[$view_root] = array_merge($treecache[$view_root], $val); } + + return $treecache[$view_root]; } /** @@ -1247,19 +1510,16 @@ function set_view_location($view, $location, $viewtype = '') { * * @param string $view_base Optional The base of the view name without the view type. * @param string $folder Required The folder to begin looking in - * @param string $base_location_path The base views directory to use with set_view_location + * @param string $base_location_path The base views directory to use with elgg_set_view_location() * @param string $viewtype The type of view we're looking at (default, rss, etc) * - * @return void + * @return bool returns false if folder can't be read * @since 1.7.0 - * @see set_view_location() + * @see elgg_set_view_location() * @todo This seems overly complicated. + * @access private */ function autoregister_views($view_base, $folder, $base_location_path, $viewtype) { - if (!isset($i)) { - $i = 0; - } - if ($handle = opendir($folder)) { while ($view = readdir($handle)) { if (!in_array($view, array('.', '..', '.svn', 'CVS')) && !is_dir($folder . "/" . $view)) { @@ -1272,7 +1532,7 @@ function autoregister_views($view_base, $folder, $base_location_path, $viewtype) $view_base_new = ""; } - set_view_location($view_base_new . str_replace('.php', '', $view), + elgg_set_view_location($view_base_new . str_replace('.php', '', $view), $base_location_path, $viewtype); } } else if (!in_array($view, array('.', '..', '.svn', 'CVS')) && is_dir($folder . "/" . $view)) { @@ -1292,87 +1552,42 @@ function autoregister_views($view_base, $folder, $base_location_path, $viewtype) } /** - * Assembles and outputs a full page. + * Add the rss link to the extras when if needed * - * A "page" in Elgg is determined by the current view type and - * can be HTML for a browser, RSS for a feed reader, or - * Javascript, PHP and a number of other formats. - * - * @param string $title Title - * @param string $body Body - * @param string $page_shell Optional page shell to use. See page_shells view directory - * @param array $vars Optional vars array to pass to the page - * shell. Automatically adds title, body, and sysmessages - * - * @return string The contents of the page - * @since 1.8 + * @return void + * @access private */ -function elgg_view_page($title, $body, $page_shell = 'default', $vars = array()) { - - if (count_messages()) { - // get messages - try for errors first - $sysmessages = system_messages(NULL, "errors"); - if (count($sysmessages["errors"]) == 0) { - // no errors so grab rest of messages - $sysmessages = system_messages(null, ""); +function elgg_views_add_rss_link() { + global $autofeed; + if (isset($autofeed) && $autofeed == true) { + $url = current_page_url(); + if (substr_count($url, '?')) { + $url .= "&view=rss"; } else { - // we have errors - clear out remaining messages - system_messages(null, ""); + $url .= "?view=rss"; } - } - - $vars['title'] = $title; - $vars['body'] = $body; - $vars['sysmessages'] = $sysmessages; - // Draw the page - $output = elgg_view("page_shells/$page_shell", $vars); - - $vars['page_shell'] = $page_shell; - - // Allow plugins to mod output - return elgg_trigger_plugin_hook('output', 'page', $vars, $output); -} - -/** - * @deprecated 1.8 Use elgg_view_page() - */ -function page_draw($title, $body, $sidebar = "") { - elgg_deprecated_notice("page_draw() was deprecated in favor of elgg_view_page() in 1.8.", 1.8); - - $vars = array( - 'sidebar' => $sidebar - ); - echo elgg_view_page($title, $body, 'default', $vars); + $url = elgg_format_url($url); + elgg_register_menu_item('extras', array( + 'name' => 'rss', + 'text' => elgg_view_icon('rss'), + 'href' => $url, + 'title' => elgg_echo('feed:rss'), + )); + } } /** - * Checks if $view_type is valid on this installation. + * Registers deprecated views to avoid making some pages from older plugins + * completely empty. * - * @param string $view_type View type - * - * @return bool - * @since 1.7.2 + * @access private */ -function elgg_is_valid_view_type($view_type) { - global $CONFIG; - - if (!isset($CONFIG->view_types) || !is_array($CONFIG->view_types)) { - return FALSE; +function elgg_views_handle_deprecated_views() { + $location = elgg_get_view_location('page_elements/contentwrapper'); + if ($location === "/var/www/views/") { + elgg_extend_view('page_elements/contentwrapper', 'page/elements/wrapper'); } - - return in_array($view_type, $CONFIG->view_types); -} - -/** - * Add the core Elgg head elements that could be cached - */ -function elgg_views_register_core_head_elements() { - $url = elgg_view_get_simplecache_url('js', 'initialise_elgg'); - elgg_register_js($url, 'initialise_elgg'); - - $url = elgg_view_get_simplecache_url('css', 'screen'); - elgg_register_css($url, 'screen'); } /** @@ -1386,31 +1601,65 @@ function elgg_views_register_core_head_elements() { function elgg_views_boot() { global $CONFIG; - elgg_view_register_simplecache('css/screen'); - elgg_view_register_simplecache('css/ie'); - elgg_view_register_simplecache('css/ie6'); - elgg_view_register_simplecache('js/friendsPickerv1'); - elgg_view_register_simplecache('js/initialise_elgg'); + elgg_register_simplecache_view('css/ie'); + elgg_register_simplecache_view('css/ie6'); + elgg_register_simplecache_view('css/ie7'); + + elgg_register_js('jquery', '/vendors/jquery/jquery-1.6.4.min.js', 'head'); + elgg_register_js('jquery-ui', '/vendors/jquery/jquery-ui-1.8.16.min.js', 'head'); + elgg_register_js('jquery.form', '/vendors/jquery/jquery.form.js'); + + elgg_register_simplecache_view('js/elgg'); + $elgg_js_url = elgg_get_simplecache_url('js', 'elgg'); + elgg_register_js('elgg', $elgg_js_url, 'head'); + + elgg_load_js('jquery'); + elgg_load_js('jquery-ui'); + elgg_load_js('elgg'); - $base = elgg_get_site_url(); - elgg_register_js("{$base}vendors/jquery/jquery-1.4.2.min.js", 'jquery'); - elgg_register_js("{$base}vendors/jquery/jquery-ui-1.7.2.min.js", 'jquery-ui'); - elgg_register_js("{$base}vendors/jquery/jquery.form.js", 'jquery.form'); + elgg_register_simplecache_view('js/lightbox'); + $lightbox_js_url = elgg_get_simplecache_url('js', 'lightbox'); + elgg_register_js('lightbox', $lightbox_js_url); - elgg_register_event_handler('pagesetup', 'system', 'elgg_views_register_core_head_elements'); + elgg_register_simplecache_view('css/lightbox'); + $lightbox_css_url = elgg_get_simplecache_url('css', 'lightbox'); + elgg_register_css('lightbox', $lightbox_css_url); + + elgg_register_simplecache_view('css/elgg'); + $elgg_css_url = elgg_get_simplecache_url('css', 'elgg'); + elgg_register_css('elgg', $elgg_css_url); + + elgg_load_css('elgg'); + + elgg_register_ajax_view('js/languages'); + + elgg_register_plugin_hook_handler('output:before', 'layout', 'elgg_views_add_rss_link'); // discover the built-in view types - // @todo cache this + // @todo the cache is loaded in load_plugins() but we need to know view_types earlier $view_path = $CONFIG->viewpath; - $CONFIG->view_types = array(); $views = scandir($view_path); foreach ($views as $view) { - if ('.' !== substr($view, 0, 1) && is_dir($view_path . $view)) { - $CONFIG->view_types[] = $view; + if ($view[0] !== '.' && is_dir($view_path . $view)) { + elgg_register_viewtype($view); } } + + // set default icon sizes - can be overridden in settings.php or with plugin + if (!isset($CONFIG->icon_sizes)) { + $icon_sizes = array( + 'topbar' => array('w' => 16, 'h' => 16, 'square' => TRUE, 'upscale' => TRUE), + 'tiny' => array('w' => 25, 'h' => 25, 'square' => TRUE, 'upscale' => TRUE), + 'small' => array('w' => 40, 'h' => 40, 'square' => TRUE, 'upscale' => TRUE), + 'medium' => array('w' => 100, 'h' => 100, 'square' => TRUE, 'upscale' => TRUE), + 'large' => array('w' => 200, 'h' => 200, 'square' => FALSE, 'upscale' => FALSE), + 'master' => array('w' => 550, 'h' => 550, 'square' => FALSE, 'upscale' => FALSE), + ); + elgg_set_config('icon_sizes', $icon_sizes); + } } -elgg_register_event_handler('boot', 'system', 'elgg_views_boot', 1000);
\ No newline at end of file +elgg_register_event_handler('boot', 'system', 'elgg_views_boot'); +elgg_register_event_handler('init', 'system', 'elgg_views_handle_deprecated_views'); |
