PageRenderTime 36ms CodeModel.GetById 4ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 1ms

/engine/lib/views.php

https://github.com/blacktooth/Elgg
PHP | 1589 lines | 700 code | 194 blank | 695 comment | 180 complexity | 3bed72cfa62de4c77f1a0670b0bccce8 MD5 | raw file
   1<?php
   2/**
   3 * Elgg's view system.
   4 *
   5 * The view system is the primary templating engine in Elgg and renders
   6 * all output.  Views are short, parameterised PHP scripts for displaying
   7 * output that can be regsitered, overridden, or extended.  The view type
   8 * determines the output format and location of the files that renders the view.
   9 *
  10 * Elgg uses a two step process to render full output: first
  11 * content-specific elements are rendered, then the resulting
  12 * content is inserted into a layout and displayed.  This makes it
  13 * easy to maintain a consistent look on all pages.
  14 *
  15 * A view corresponds to a single file on the filesystem and the views
  16 * name is its directory structure.  A file in
  17 * <code>mod/plugins/views/default/myplugin/example.php</code>
  18 * is called by saying (with the default viewtype):
  19 * <code>echo elgg_view('myplugin/example');</code>
  20 *
  21 * View names that are registered later override those that are
  22 * registered earlier.  For plugins this corresponds directly
  23 * to their load order: views in plugins lower in the list override
  24 * those higher in the list.
  25 *
  26 * Plugin views belong in the views/ directory under an appropriate
  27 * viewtype.  Views are automatically registered.
  28 *
  29 * Views can be embedded-you can call a view from within a view.
  30 * Views can also be prepended or extended by any other view.
  31 *
  32 * Any view can extend any other view if registered with
  33 * {@link elgg_extend_view()}.
  34 *
  35 * View types are set by passing $_REQUEST['view'].  The view type
  36 * 'default' is a standard HTML view.  Types can be defined on the fly
  37 * and you can get the current view type with {@link get_current_view()}.
  38 *
  39 * @internal Plugin views are autoregistered before their init functions
  40 * are called, so the init order doesn't affect views.
  41 *
  42 * @internal The file that determines the output of the view is the last
  43 * registered by {@link elgg_set_view_location()}.
  44 *
  45 * @package Elgg.Core
  46 * @subpackage Views
  47 * @link http://docs.elgg.org/Views
  48 */
  49
  50/**
  51 * The view type override.
  52 *
  53 * @global string $CURRENT_SYSTEM_VIEWTYPE
  54 * @see elgg_set_viewtype()
  55 */
  56global $CURRENT_SYSTEM_VIEWTYPE;
  57$CURRENT_SYSTEM_VIEWTYPE = "";
  58
  59/**
  60 * Manually set the viewtype.
  61 *
  62 * View types are detected automatically.  This function allows
  63 * you to force subsequent views to use a different viewtype.
  64 *
  65 * @tip Call elgg_set_viewtype() with no parameter to reset.
  66 *
  67 * @param string $viewtype The view type, e.g. 'rss', or 'default'.
  68 *
  69 * @return bool
  70 * @link http://docs.elgg.org/Views/Viewtype
  71 * @example views/viewtype.php
  72 */
  73function elgg_set_viewtype($viewtype = "") {
  74	global $CURRENT_SYSTEM_VIEWTYPE;
  75
  76	$CURRENT_SYSTEM_VIEWTYPE = $viewtype;
  77
  78	return true;
  79}
  80
  81/**
  82 * Return the current view type.
  83 *
  84 * View types are automatically detected and can be set with $_REQUEST['view']
  85 * or {@link elgg_set_viewtype()}.
  86 *
  87 * @internal View type is determined in this order:
  88 *  - $CURRENT_SYSTEM_VIEWTYPE Any overrides by {@link elgg_set_viewtype()}
  89 *  - $CONFIG->view  The default view as saved in the DB.
  90 *  - $_SESSION['view']
  91 *
  92 * @return string The view.
  93 * @see elgg_set_viewtype()
  94 * @link http://docs.elgg.org/Views
  95 * @todo This function's sessions stuff needs rewritten, removed, or explained.
  96 */
  97function elgg_get_viewtype() {
  98	global $CURRENT_SYSTEM_VIEWTYPE, $CONFIG;
  99
 100	if ($CURRENT_SYSTEM_VIEWTYPE != "") {
 101		return $CURRENT_SYSTEM_VIEWTYPE;
 102	}
 103
 104	$viewtype = get_input('view', NULL);
 105	if ($viewtype) {
 106		return $viewtype;
 107	}
 108
 109	if (isset($CONFIG->view) && !empty($CONFIG->view)) {
 110		return $CONFIG->view;
 111	}
 112
 113	return 'default';
 114}
 115
 116/**
 117 * Register a view type as valid.
 118 *
 119 * @param string $view_type The view type to register
 120 * @return bool
 121 */
 122function elgg_register_viewtype($view_type) {
 123	global $CONFIG;
 124
 125	if (!isset($CONFIG->view_types) || !is_array($CONFIG->view_types)) {
 126		$CONFIG->view_types = array();
 127	}
 128
 129	if (!in_array($view_type, $CONFIG->view_types)) {
 130		$CONFIG->view_types[] = $view_type;
 131	}
 132
 133	return true;
 134}
 135
 136/**
 137 * Checks if $view_type is valid on this installation.
 138 *
 139 * @param string $view_type View type
 140 *
 141 * @return bool
 142 * @since 1.7.2
 143 */
 144function elgg_is_valid_view_type($view_type) {
 145	global $CONFIG;
 146
 147	if (!isset($CONFIG->view_types) || !is_array($CONFIG->view_types)) {
 148		return FALSE;
 149	}
 150
 151	return in_array($view_type, $CONFIG->view_types);
 152}
 153
 154/**
 155 * Register a viewtype to fall back to a default view if a view isn't
 156 * found for that viewtype.
 157 *
 158 * @tip This is useful for alternate html viewtypes (such as for mobile devices).
 159 *
 160 * @param string $viewtype The viewtype to register
 161 *
 162 * @return void
 163 * @since 1.7.2
 164 * @example views/viewtype_fallback.php Fallback from mobile to default.
 165 */
 166function elgg_register_viewtype_fallback($viewtype) {
 167	global $CONFIG;
 168
 169	if (!isset($CONFIG->viewtype)) {
 170		$CONFIG->viewtype = new stdClass;
 171	}
 172
 173	if (!isset($CONFIG->viewtype->fallback)) {
 174		$CONFIG->viewtype->fallback = array();
 175	}
 176
 177	$CONFIG->viewtype->fallback[] = $viewtype;
 178}
 179
 180/**
 181 * Checks if a viewtype falls back to default.
 182 *
 183 * @param string $viewtype Viewtype
 184 *
 185 * @return boolean
 186 * @since 1.7.2
 187 */
 188function elgg_does_viewtype_fallback($viewtype) {
 189	global $CONFIG;
 190
 191	if (isset($CONFIG->viewtype) && isset($CONFIG->viewtype->fallback)) {
 192		return in_array($viewtype, $CONFIG->viewtype->fallback);
 193	}
 194
 195	return FALSE;
 196}
 197
 198
 199/**
 200 * Returns the file location for a view.
 201 *
 202 * @warning This doesn't check if the file exists, but only
 203 * constructs (or extracts) the path and returns it.
 204 *
 205 * @param string $view     The view.
 206 * @param string $viewtype The viewtype
 207 *
 208 * @return string
 209 */
 210function elgg_get_view_location($view, $viewtype = '') {
 211	global $CONFIG;
 212
 213	if (empty($viewtype)) {
 214		$viewtype = elgg_get_viewtype();
 215	}
 216
 217	if (!isset($CONFIG->views->locations[$viewtype][$view])) {
 218		if (!isset($CONFIG->viewpath)) {
 219			return dirname(dirname(dirname(__FILE__))) . "/views/";
 220		} else {
 221			return $CONFIG->viewpath;
 222		}
 223	} else {
 224		return $CONFIG->views->locations[$viewtype][$view];
 225	}
 226
 227	return false;
 228}
 229
 230/**
 231 * Set an alternative base location for a view.
 232 *
 233 * Views are expected to be in plugin_name/views/.  This function can
 234 * be used to change that location.
 235 *
 236 * @internal Core view locations are stored in $CONFIG->viewpath.
 237 *
 238 * @tip This is useful to optionally register views in a plugin.
 239 *
 240 * @param string $view     The name of the view
 241 * @param string $location The base location path
 242 * @param string $viewtype The view type
 243 *
 244 * @return void
 245 */
 246function elgg_set_view_location($view, $location, $viewtype = '') {
 247	global $CONFIG;
 248
 249	if (empty($viewtype)) {
 250		$viewtype = 'default';
 251	}
 252
 253	if (!isset($CONFIG->views)) {
 254		$CONFIG->views = new stdClass;
 255	}
 256
 257	if (!isset($CONFIG->views->locations)) {
 258		$CONFIG->views->locations = array($viewtype => array($view => $location));
 259
 260	} else if (!isset($CONFIG->views->locations[$viewtype])) {
 261		$CONFIG->views->locations[$viewtype] = array($view => $location);
 262
 263	} else {
 264		$CONFIG->views->locations[$viewtype][$view] = $location;
 265	}
 266}
 267
 268/**
 269 * Returns whether the specified view exists
 270 *
 271 * @note If $recurse is strue, also checks if a view exists only as an extension.
 272 *
 273 * @param string $view     The view name
 274 * @param string $viewtype If set, forces the viewtype
 275 * @param bool   $recurse  If false, do not check extensions
 276 *
 277 * @return bool
 278 */
 279function elgg_view_exists($view, $viewtype = '', $recurse = true) {
 280	global $CONFIG;
 281
 282	// Detect view type
 283	if (empty($viewtype)) {
 284		$viewtype = elgg_get_viewtype();
 285	}
 286
 287	if (!isset($CONFIG->views->locations[$viewtype][$view])) {
 288		if (!isset($CONFIG->viewpath)) {
 289			$location = dirname(dirname(dirname(__FILE__))) . "/views/";
 290		} else {
 291			$location = $CONFIG->viewpath;
 292		}
 293	} else {
 294		$location = $CONFIG->views->locations[$viewtype][$view];
 295	}
 296
 297	if (file_exists($location . "{$viewtype}/{$view}.php")) {
 298		return true;
 299	}
 300
 301	// If we got here then check whether this exists as an extension
 302	// We optionally recursively check whether the extended view exists also for the viewtype
 303	if ($recurse && isset($CONFIG->views->extensions[$view])) {
 304		foreach ($CONFIG->views->extensions[$view] as $view_extension) {
 305			// do not recursively check to stay away from infinite loops
 306			if (elgg_view_exists($view_extension, $viewtype, false)) {
 307				return true;
 308			}
 309		}
 310	}
 311
 312	// Now check if the default view exists if the view is registered as a fallback
 313	if ($viewtype != 'default' && elgg_does_viewtype_fallback($viewtype)) {
 314		return elgg_view_exists($view, 'default');
 315	}
 316
 317	return false;
 318}
 319
 320/**
 321 * Return a parsed view.
 322 *
 323 * Views are rendered by a template handler and returned as strings.
 324 *
 325 * Views are called with a special $vars variable set,
 326 * which includes any variables passed as the second parameter.
 327 * For backward compatbility, the following variables are also set but we
 328 * recommend that you do not use them:
 329 *  - $vars['config'] The $CONFIG global. (Use {@link elgg_get_config()} instead).
 330 *  - $vars['url'] The site URL. (use {@link elgg_get_site_url()} instead).
 331 *  - $vars['user'] The logged in user. (use {@link elgg_get_logged_in_user_entity()} instead).
 332 *
 333 * Custom template handlers can be set with {@link set_template_handler()}.
 334 *
 335 * The output of views can be intercepted by registering for the
 336 * view, $view_name plugin hook.
 337 *
 338 * @warning Any variables in $_SESSION will override passed vars
 339 * upon name collision.  See {@trac #2124}.
 340 *
 341 * @param string  $view     The name and location of the view to use
 342 * @param array   $vars     Variables to pass to the view.
 343 * @param boolean $bypass   If set to true, elgg_view will bypass any specified
 344 *                          alternative template handler; by default, it will
 345 *                          hand off to this if requested (see set_template_handler)
 346 * @param boolean $debug    If set to true, the viewer will complain if it can't find a view
 347 * @param string  $viewtype If set, forces the viewtype for the elgg_view call to be
 348 *                          this value (default: standard detection)
 349 *
 350 * @return string The parsed view
 351 * @see set_template_handler()
 352 * @example views/elgg_view.php
 353 * @link http://docs.elgg.org/View
 354 * @todo $debug isn't used.
 355 * @todo $usercache is redundant.
 356 */
 357function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $viewtype = '') {
 358	global $CONFIG;
 359	static $usercache;
 360
 361	$view = (string)$view;
 362
 363	// basic checking for bad paths
 364	if (strpos($view, '..') !== false) {
 365		return false;
 366	}
 367
 368	$view_orig = $view;
 369
 370	// Trigger the pagesetup event
 371	if (!isset($CONFIG->pagesetupdone)) {
 372		$CONFIG->pagesetupdone = true;
 373		elgg_trigger_event('pagesetup', 'system');
 374	}
 375
 376	if (!is_array($usercache)) {
 377		$usercache = array();
 378	}
 379
 380	if (!is_array($vars)) {
 381		elgg_log("Vars in views must be an array: $view", 'ERROR');
 382		$vars = array();
 383	}
 384
 385	if (empty($vars)) {
 386		$vars = array();
 387	}
 388
 389	// @warning - plugin authors: do not expect user, config, and url to be
 390	// set by elgg_view() in the future. Instead, use elgg_get_logged_in_user_entity(),
 391	// elgg_get_config(), and elgg_get_site_url() in your views.
 392	if (!isset($vars['user'])) {
 393		$vars['user'] = elgg_get_logged_in_user_entity();
 394	}
 395	if (!isset($vars['config'])) {
 396		$vars['config'] = $CONFIG;
 397	}
 398	if (!isset($vars['url'])) {
 399		$vars['url'] = elgg_get_site_url();
 400	}
 401
 402	// full_view is the new preferred key for full view on entities @see elgg_view_entity()
 403	// check if full_view is set because that means we've already rewritten it and this is
 404	// coming from another view passing $vars directly.
 405	if (isset($vars['full']) && !isset($vars['full_view'])) {
 406		elgg_deprecated_notice("Use \$vars['full_view'] instead of \$vars['full']", 1.8, 2);
 407		$vars['full_view'] = $vars['full'];
 408	}
 409	if (isset($vars['full_view'])) {
 410		$vars['full'] = $vars['full_view'];
 411	}
 412
 413	// internalname => name (1.8)
 414	if (isset($vars['internalname']) && !isset($vars['name'])) {
 415		elgg_deprecated_notice('You should pass $vars[\'name\'] now instead of $vars[\'internalname\']', 1.8, 2);
 416		$vars['name'] = $vars['internalname'];
 417		$test=false;
 418	} elseif (isset($vars['name'])) {
 419		$vars['internalname'] = $vars['name'];
 420	}
 421
 422	// internalid => id (1.8)
 423	if (isset($vars['internalid']) && !isset($vars['name'])) {
 424		elgg_deprecated_notice('You should pass $vars[\'id\'] now instead of $vars[\'internalid\']', 1.8, 2);
 425		$vars['id'] = $vars['internalid'];
 426	} elseif (isset($vars['id'])) {
 427		$vars['internalid'] = $vars['id'];
 428	}
 429
 430	// If it's been requested, pass off to a template handler instead
 431	if ($bypass == false && isset($CONFIG->template_handler) && !empty($CONFIG->template_handler)) {
 432		$template_handler = $CONFIG->template_handler;
 433		if (is_callable($template_handler)) {
 434			return call_user_func($template_handler, $view, $vars);
 435		}
 436	}
 437
 438	// Get the current viewtype
 439	if (empty($viewtype)) {
 440		$viewtype = elgg_get_viewtype();
 441	}
 442
 443	// Viewtypes can only be alphanumeric
 444	if (preg_match('[\W]', $viewtype)) {
 445		return '';
 446	}
 447
 448	// Set up any extensions to the requested view
 449	if (isset($CONFIG->views->extensions[$view])) {
 450		$viewlist = $CONFIG->views->extensions[$view];
 451	} else {
 452		$viewlist = array(500 => $view);
 453	}
 454
 455	// Start the output buffer, find the requested view file, and execute it
 456	ob_start();
 457
 458	foreach ($viewlist as $priority => $view) {
 459		$view_location = elgg_get_view_location($view, $viewtype);
 460		$view_file = "$view_location$viewtype/$view.php";
 461
 462		$default_location = elgg_get_view_location($view, 'default');
 463		$default_view_file = "{$default_location}default/$view.php";
 464
 465		// try to include view
 466		if (!file_exists($view_file) || !include($view_file)) {
 467			// requested view does not exist
 468			$error = "$viewtype/$view view does not exist.";
 469
 470			// attempt to load default view
 471			if ($viewtype != 'default' && elgg_does_viewtype_fallback($viewtype)) {
 472				if (file_exists($default_view_file) && include($default_view_file)) {
 473					// default view found
 474					$error .= " Using default/$view instead.";
 475				} else {
 476					// no view found at all
 477					$error = "Neither $viewtype/$view nor default/$view view exists.";
 478				}
 479			}
 480
 481			// log warning
 482			elgg_log($error, 'NOTICE');
 483		}
 484	}
 485
 486	// Save the output buffer into the $content variable
 487	$content = ob_get_clean();
 488
 489	// Plugin hook
 490	$params = array('view' => $view_orig, 'vars' => $vars, 'viewtype' => $viewtype);
 491	$content = elgg_trigger_plugin_hook('view', $view_orig, $params, $content);
 492
 493	// backward compatibility with less granular hook will be gone in 2.0
 494	$content_tmp = elgg_trigger_plugin_hook('display', 'view', $params, $content);
 495
 496	if ($content_tmp != $content) {
 497		$content = $content_tmp;
 498		elgg_deprecated_notice('The display:view plugin hook is deprecated by view:view_name', 1.8);
 499	}
 500
 501	return $content;
 502}
 503
 504/**
 505 * Extends a view with another view.
 506 *
 507 * The output of any view can be prepended or appended to any other view.
 508 *
 509 * The default action is to append a view.  If the priority is less than 500,
 510 * the output of the extended view will be appended to the original view.
 511 *
 512 * Priority can be specified and affects the order in which extensions
 513 * are appended or prepended.
 514 *
 515 * @internal View extensions are stored in
 516 * $CONFIG->views->extensions[$view][$priority] = $view_extension
 517 *
 518 * @param string $view           The view to extend.
 519 * @param string $view_extension This view is added to $view
 520 * @param int    $priority       The priority, from 0 to 1000,
 521 *                               to add at (lowest numbers displayed first)
 522 * @param string $viewtype       Not used
 523 *
 524 * @return void
 525 * @since 1.7.0
 526 * @link http://docs.elgg.org/Views/Ejxtend
 527 * @example views/extend.php
 528 */
 529function elgg_extend_view($view, $view_extension, $priority = 501, $viewtype = '') {
 530	global $CONFIG;
 531
 532	if (!isset($CONFIG->views)) {
 533		$CONFIG->views = new stdClass;
 534	}
 535
 536	if (!isset($CONFIG->views->extensions)) {
 537		$CONFIG->views->extensions = array();
 538	}
 539
 540	if (!isset($CONFIG->views->extensions[$view])) {
 541		$CONFIG->views->extensions[$view][500] = "{$view}";
 542	}
 543
 544	while (isset($CONFIG->views->extensions[$view][$priority])) {
 545		$priority++;
 546	}
 547
 548	$CONFIG->views->extensions[$view][$priority] = "{$view_extension}";
 549	ksort($CONFIG->views->extensions[$view]);
 550}
 551
 552/**
 553 * Unextends a view.
 554 *
 555 * @param string $view           The view that was extended.
 556 * @param string $view_extension This view that was added to $view
 557 *
 558 * @return bool
 559 * @since 1.7.2
 560 */
 561function elgg_unextend_view($view, $view_extension) {
 562	global $CONFIG;
 563
 564	if (!isset($CONFIG->views)) {
 565		return FALSE;
 566	}
 567
 568	if (!isset($CONFIG->views->extensions)) {
 569		return FALSE;
 570	}
 571
 572	if (!isset($CONFIG->views->extensions[$view])) {
 573		return FALSE;
 574	}
 575
 576	$priority = array_search($view_extension, $CONFIG->views->extensions[$view]);
 577	if ($priority === FALSE) {
 578		return FALSE;
 579	}
 580
 581	unset($CONFIG->views->extensions[$view][$priority]);
 582
 583	return TRUE;
 584}
 585
 586/**
 587 * Assembles and outputs a full page.
 588 *
 589 * A "page" in Elgg is determined by the current view type and
 590 * can be HTML for a browser, RSS for a feed reader, or
 591 * Javascript, PHP and a number of other formats.
 592 *
 593 * @param string $title      Title
 594 * @param string $body       Body
 595 * @param string $page_shell Optional page shell to use. See page/shells view directory
 596 * @param array  $vars       Optional vars array to pass to the page
 597 *                           shell. Automatically adds title, body, and sysmessages
 598 *
 599 * @return string The contents of the page
 600 * @since  1.8
 601 */
 602function elgg_view_page($title, $body, $page_shell = 'default', $vars = array()) {
 603
 604	$messages = null;
 605	if (count_messages()) {
 606		// get messages - try for errors first
 607		$messages = system_messages(NULL, "error");
 608		if (count($messages["error"]) == 0) {
 609			// no errors so grab rest of messages
 610			$messages = system_messages(null, "");
 611		} else {
 612			// we have errors - clear out remaining messages
 613			system_messages(null, "");
 614		}
 615	}
 616
 617	$vars['title'] = $title;
 618	$vars['body'] = $body;
 619	$vars['sysmessages'] = $messages;
 620
 621	$vars = elgg_trigger_plugin_hook('output:before', 'page', null, $vars);
 622	
 623	// check for deprecated view
 624	if ($page_shell == 'default' && elgg_view_exists('pageshells/pageshell')) {
 625		elgg_deprecated_notice("pageshells/pageshell is deprecated by page/$page_shell", 1.8);
 626		$output = elgg_view('pageshells/pageshell', $vars);
 627	} else {
 628		$output = elgg_view("page/$page_shell", $vars);
 629	}
 630
 631	$vars['page_shell'] = $page_shell;
 632
 633	// Allow plugins to mod output
 634	return elgg_trigger_plugin_hook('output', 'page', $vars, $output);
 635}
 636
 637/**
 638 * Displays a layout with optional parameters.
 639 *
 640 * Layouts provide consistent organization of pages and other blocks of content.
 641 * There are a few default layouts in core:
 642 *  - admin                   A special layout for the admin area.
 643 *  - one_column              A single content column.
 644 *  - one_sidebar             A content column with sidebar.
 645 *  - two_sidebar             A content column with two sidebars.
 646 *  - widgets                 A widget canvas.
 647 *
 648 * The layout views take the form page/layouts/$layout_name
 649 * See the individual layouts for what options are supported. The three most
 650 * common layouts have these parameters:
 651 * one_column
 652 *     content => string
 653 * one_sidebar
 654 *     content => string
 655 *     sidebar => string (optional)
 656 * content
 657 *     content => string
 658 *     sidebar => string (optional)
 659 *     buttons => string (override the default add button)
 660 *     title   => string (override the default title)
 661 *     filter_context => string (selected content filter)
 662 *     See the content layout view for more parameters
 663 *
 664 * @param string $layout_name The name of the view in page/layouts/.
 665 * @param array  $vars        Associative array of parameters for the layout view
 666 *
 667 * @return string The layout
 668 */
 669function elgg_view_layout($layout_name, $vars = array()) {
 670
 671	if (is_string($vars) || $vars === null) {
 672		elgg_deprecated_notice("The use of unlimited optional string arguments in elgg_view_layout() was deprecated in favor of an options array", 1.8);
 673		$arg = 1;
 674		$param_array = array();
 675		while ($arg < func_num_args()) {
 676			$param_array['area' . $arg] = func_get_arg($arg);
 677			$arg++;
 678		}
 679	} else {
 680		$param_array = $vars;
 681	}
 682
 683	$params = elgg_trigger_plugin_hook('output:before', 'layout', null, $param_array);
 684
 685	// check deprecated location
 686	if (elgg_view_exists("canvas/layouts/$layout_name")) {
 687		elgg_deprecated_notice("canvas/layouts/$layout_name is deprecated by page/layouts/$layout_name", 1.8);
 688		$output = elgg_view("canvas/layouts/$layout_name", $params);
 689	} elseif (elgg_view_exists("page/layouts/$layout_name")) {
 690		$output = elgg_view("page/layouts/$layout_name", $params);
 691	} else {
 692		$output = elgg_view("page/layouts/default", $params);
 693	}
 694
 695	return elgg_trigger_plugin_hook('output:after', 'layout', $params, $output);
 696}
 697
 698/**
 699 * Render a menu
 700 *
 701 * @see elgg_register_menu_item() for documentation on adding menu items and
 702 * navigation.php for information on the different menus available.
 703 *
 704 * This function triggers a 'register', 'menu:<menu name>' plugin hook that enables
 705 * plugins to add menu items just before a menu is rendered. This is used by
 706 * context-sensitive menus (menus that are specific to a particular entity such
 707 * as the user hover menu). Using elgg_register_menu_item() in response to the hook
 708 * can cause incorrect links to show up. See the blog plugin's blog_owner_block_menu()
 709 * for an example of using this plugin hook.
 710 *
 711 * An additional hook is the 'prepare', 'menu:<menu name>' which enables plugins
 712 * to modify the structure of the menu (sort it, remove items, set variables on
 713 * the menu items).
 714 *
 715 * elgg_view_menu() uses views in navigation/menu
 716 *
 717 * @param string $menu_name The name of the menu
 718 * @param array  $vars      An associative array of display options for the menu.
 719 *                          Options include:
 720 *                              sort_by => string or php callback
 721 *                                  string options: 'name', 'priority', 'title' (default), 'register' (registration order)
 722 *                                  php callback: a compare function for usort
 723 *                              handler: string the page handler to build action URLs
 724 *                              entity: ElggEntity to use to build action URLs
 725 *                              class: string the class for the entire menu.
 726 *                              show_section_headers: bool show headers before menu sections.
 727 *
 728 * @return string
 729 * @since 1.8.0
 730 */
 731function elgg_view_menu($menu_name, array $vars = array()) {
 732	global $CONFIG;
 733
 734	$vars['name'] = $menu_name;
 735
 736	$sort_by = elgg_extract('sort_by', $vars, 'text');
 737
 738	$menu = $CONFIG->menus[$menu_name];
 739
 740	// Give plugins a chance to add menu items just before creation.
 741	// This supports context sensitive menus (ex. user_hover).
 742	$menu = elgg_trigger_plugin_hook('register', "menu:$menu_name", $vars, $menu);
 743
 744	$builder = new ElggMenuBuilder($menu);
 745	$vars['menu'] = $builder->getMenu($sort_by);
 746	$vars['selected_item'] = $builder->getSelected();
 747
 748	// Let plugins modify the menu
 749	$vars['menu'] = elgg_trigger_plugin_hook('prepare', "menu:$menu_name", $vars, $vars['menu']);
 750
 751	if (elgg_view_exists("navigation/menu/$menu_name")) {
 752		return elgg_view("navigation/menu/$menu_name", $vars);
 753	} else {
 754		return elgg_view("navigation/menu/default", $vars);
 755	}
 756}
 757
 758/**
 759 * Returns a string of a rendered entity.
 760 *
 761 * Entity views are either determined by setting the view property on the entity
 762 * or by having a view named after the entity $type/$subtype.  Entities that have
 763 * neither a view property nor a defined $type/$subtype view will fall back to
 764 * using the $type/default view.
 765 *
 766 * The entity view is called with the following in $vars:
 767 *  - ElggEntity 'entity' The entity being viewed
 768 *
 769 * Other common view $vars paramters:
 770 *  - bool 'full_view' Whether to show a full or condensed view.
 771 *
 772 * @tip This function can automatically appends annotations to entities if in full
 773 * view and a handler is registered for the entity:annotate.  See {@trac 964} and
 774 * {@link elgg_view_entity_annotations()}.
 775 *
 776 * @param ElggEntity $entity The entity to display
 777 * @param array      $vars   Array of variables to pass to the entity view.
 778 *                           In Elgg 1.7 and earlier it was the boolean $full_view
 779 * @param boolean    $bypass If false, will not pass to a custom template handler.
 780 *                           {@see set_template_handler()}
 781 * @param boolean    $debug  Complain if views are missing
 782 *
 783 * @return string HTML to display or false
 784 * @link http://docs.elgg.org/Views/Entity
 785 * @link http://docs.elgg.org/Entities
 786 * @todo The annotation hook might be better as a generic plugin hook to append content.
 787 */
 788function elgg_view_entity(ElggEntity $entity, $vars = array(), $bypass = true, $debug = false) {
 789
 790	// No point continuing if entity is null
 791	if (!$entity || !($entity instanceof ElggEntity)) {
 792		return false;
 793	}
 794
 795	global $autofeed;
 796	$autofeed = true;
 797
 798	$defaults = array(
 799		'full_view' => false,
 800	);
 801
 802	if (is_array($vars)) {
 803		$vars = array_merge($defaults, $vars);
 804	} else {
 805		elgg_deprecated_notice("Update your use of elgg_view_entity()", 1.8);
 806		$vars = array(
 807			'full_view' => $vars,
 808		);
 809	}
 810
 811	$vars['entity'] = $entity;
 812
 813
 814	// if this entity has a view defined, use it
 815	$view = $entity->view;
 816	if (is_string($view)) {
 817		return elgg_view($view, $vars, $bypass, $debug);
 818	}
 819
 820	$entity_type = $entity->getType();
 821
 822	$subtype = $entity->getSubtype();
 823	if (empty($subtype)) {
 824		$subtype = 'default';
 825	}
 826
 827	$contents = '';
 828	if (elgg_view_exists("$entity_type/$subtype")) {
 829		$contents = elgg_view("$entity_type/$subtype", $vars, $bypass, $debug);
 830	}
 831	if (empty($contents)) {
 832		$contents = elgg_view("$entity_type/default", $vars, $bypass, $debug);
 833	}
 834
 835	// Marcus Povey 20090616 : Speculative and low impact approach for fixing #964
 836	if ($vars['full_view']) {
 837		$annotations = elgg_view_entity_annotations($entity, $vars['full_view']);
 838
 839		if ($annotations) {
 840			$contents .= $annotations;
 841		}
 842	}
 843	return $contents;
 844}
 845
 846/**
 847 * View the icon of an entity
 848 *
 849 * Entity views are determined by having a view named after the entity $type/$subtype.
 850 * Entities that do not have a defined icon/$type/$subtype view will fall back to using
 851 * the icon/$type/default view.
 852 *
 853 * @param ElggEntity $entity The entity to display
 854 * @param string     $size   The size: tiny, small, medium, large
 855 * @param array      $vars   An array of variables to pass to the view
 856 *
 857 * @return string HTML to display or false
 858 */
 859function elgg_view_entity_icon(ElggEntity $entity, $size = 'medium', $vars = array()) {
 860
 861	// No point continuing if entity is null
 862	if (!$entity || !($entity instanceof ElggEntity)) {
 863		return false;
 864	}
 865
 866	$vars['entity'] = $entity;
 867	$vars['size'] = $size;
 868
 869	$entity_type = $entity->getType();
 870
 871	$subtype = $entity->getSubtype();
 872	if (empty($subtype)) {
 873		$subtype = 'default';
 874	}
 875
 876	$contents = '';
 877	if (elgg_view_exists("icon/$entity_type/$subtype")) {
 878		$contents = elgg_view("icon/$entity_type/$subtype", $vars);
 879	}
 880	if (empty($contents)) {
 881		$contents = elgg_view("icon/$entity_type/default", $vars);
 882	}
 883	if (empty($contents)) {
 884		$contents = elgg_view("icon/default", $vars);
 885	}
 886
 887	return $contents;
 888}
 889
 890/**
 891 * Returns a string of a rendered annotation.
 892 *
 893 * Annotation views are expected to be in annotation/$annotation_name.
 894 * If a view is not found for $annotation_name, the default annotation/default
 895 * will be used.
 896 *
 897 * @warning annotation/default is not currently defined in core.
 898 *
 899 * The annotation view is called with the following in $vars:
 900 *  - ElggEntity 'annotation' The annotation being viewed.
 901 *
 902 * @param ElggAnnotation $annotation The annotation to display
 903 * @param array          $vars       Variable array for view.
 904 * @param bool           $bypass     If false, will not pass to a custom
 905 *                                   template handler. {@see set_template_handler()}
 906 * @param bool           $debug      Complain if views are missing
 907 *
 908 * @return string/false Rendered annotation
 909 */
 910function elgg_view_annotation(ElggAnnotation $annotation, array $vars = array(), $bypass = true, $debug = false) {
 911	global $autofeed;
 912	$autofeed = true;
 913
 914	$defaults = array(
 915		'full_view' => true,
 916	);
 917
 918	$vars = array_merge($defaults, $vars);
 919	$vars['annotation'] = $annotation;
 920
 921	// @todo setting the view on an annotation is not advertised anywhere
 922	// do we want to keep this?
 923	$view = $annotation->view;
 924	if (is_string($view)) {
 925		return elgg_view($view, $vars, $bypass, $debug);
 926	}
 927
 928	// @todo would be better to always make sure name is initialized properly
 929	$name = $annotation->name;
 930	$intname = (int) $name;
 931	if ("{$intname}" == "{$name}") {
 932		$name = get_metastring($intname);
 933	}
 934	if (empty($name)) {
 935		return false;
 936	}
 937
 938	if (elgg_view_exists("annotation/$name")) {
 939		return elgg_view("annotation/$name", $vars, $bypass, $debug);
 940	} else {
 941		return elgg_view("annotation/default", $vars, $bypass, $debug);
 942	}
 943}
 944
 945/**
 946 * Returns a rendered list of entities with pagination. This function should be
 947 * called by wrapper functions.
 948 *
 949 * @see elgg_list_entities()
 950 * @see list_user_friends_objects()
 951 * @see elgg_list_entities_from_metadata()
 952 * @see elgg_list_entities_from_relationships()
 953 * @see elgg_list_entities_from_annotations()
 954 *
 955 * @param array $entities Array of entities
 956 * @param array $vars     Display variables
 957 *		'count'            The total number of entities across all pages
 958 *		'offset'           The current indexing offset
 959 *		'limit'            The number of entities to display per page
 960 *		'full_view'        Display the full view of the entities?
 961 *		'list_class'       CSS class applied to the list
 962 *		'item_class'       CSS class applied to the list items
 963 *		'pagination'       Display pagination?
 964 *		'list_type'        List type: 'list' (default), 'gallery'
 965 *		'list_type_toggle' Display the list type toggle?
 966 *
 967 * @return string The rendered list of entities
 968 * @access private
 969 */
 970function elgg_view_entity_list($entities, $vars = array(), $offset = 0, $limit = 10, $full_view = true,
 971$list_type_toggle = true, $pagination = true) {
 972
 973	if (!is_int($offset)) {
 974		$offset = (int)get_input('offset', 0);
 975	}
 976
 977	// list type can be passed as request parameter
 978	$list_type = get_input('list_type', 'list');
 979	if (get_input('listtype')) {
 980		elgg_deprecated_notice("'listtype' has been deprecated by 'list_type' for lists", 1.8);
 981		$list_type = get_input('listtype');
 982	}
 983
 984	if (is_array($vars)) {
 985		// new function
 986		$defaults = array(
 987			'items' => $entities,
 988			'list_class' => 'elgg-list-entity',
 989			'full_view' => true,
 990			'pagination' => true,
 991			'list_type' => $list_type,
 992			'list_type_toggle' => false,
 993			'offset' => $offset,
 994		);
 995
 996		$vars = array_merge($defaults, $vars);
 997
 998	} else {
 999		// old function parameters
1000		elgg_deprecated_notice("Please update your use of elgg_view_entity_list()", 1.8);
1001
1002		$vars = array(
1003			'items' => $entities,
1004			'count' => (int) $vars, // the old count parameter
1005			'offset' => $offset,
1006			'limit' => (int) $limit,
1007			'full_view' => $full_view,
1008			'pagination' => $pagination,
1009			'list_type' => $list_type,
1010			'list_type_toggle' => $list_type_toggle,
1011			'list_class' => 'elgg-list-entity',
1012		);
1013	}
1014
1015	if ($vars['list_type'] != 'list') {
1016		return elgg_view('page/components/gallery', $vars);
1017	} else {
1018		return elgg_view('page/components/list', $vars);
1019	}
1020}
1021
1022/**
1023 * Returns a rendered list of annotations, plus pagination. This function
1024 * should be called by wrapper functions.
1025 *
1026 * @param array $annotations Array of annotations
1027 * @param array $vars        Display variables
1028 *		'count'      The total number of annotations across all pages
1029 *		'offset'     The current indexing offset
1030 *		'limit'      The number of annotations to display per page
1031 *		'full_view'  Display the full view of the annotation?
1032 *		'list_class' CSS Class applied to the list
1033 *		'offset_key' The url parameter key used for offset
1034 *
1035 * @return string The list of annotations
1036 * @access private
1037 */
1038function elgg_view_annotation_list($annotations, array $vars = array()) {
1039	$defaults = array(
1040		'items' => $annotations,
1041		'list_class' => 'elgg-annotation-list',
1042		'full_view' => true,
1043		'offset_key' => 'annoff',
1044	);
1045
1046	$vars = array_merge($defaults, $vars);
1047
1048	return elgg_view('page/components/list', $vars);
1049}
1050
1051/**
1052 * Display a plugin-specified rendered list of annotations for an entity.
1053 *
1054 * This displays the output of functions registered to the entity:annotation,
1055 * $entity_type plugin hook.
1056 *
1057 * This is called automatically by the framework from {@link elgg_view_entity()}
1058 *
1059 * @param ElggEntity $entity    Entity
1060 * @param bool       $full_view Display full view?
1061 *
1062 * @return mixed string or false on failure
1063 * @todo Change the hook name.
1064 */
1065function elgg_view_entity_annotations(ElggEntity $entity, $full_view = true) {
1066	if (!$entity) {
1067		return false;
1068	}
1069
1070	if (!($entity instanceof ElggEntity)) {
1071		return false;
1072	}
1073
1074	$entity_type = $entity->getType();
1075
1076	$annotations = elgg_trigger_plugin_hook('entity:annotate', $entity_type,
1077		array(
1078			'entity' => $entity,
1079			'full_view' => $full_view,
1080		)
1081	);
1082
1083	return $annotations;
1084}
1085
1086/**
1087 * Renders a title.
1088 *
1089 * This is a shortcut for {@elgg_view page/elements/title}.
1090 *
1091 * @param string $title The page title
1092 * @param string $vars  View variables (was submenu be displayed? (deprecated))
1093 *
1094 * @return string The HTML (etc)
1095 */
1096function elgg_view_title($title, $vars = array()) {
1097	if (!is_array($vars)) {
1098		elgg_deprecated_notice('setting $submenu in elgg_view_title() is deprecated', 1.8);
1099		$vars = array('submenu' => $vars);
1100	}
1101
1102	$vars['title'] = $title;
1103
1104	return elgg_view('page/elements/title', $vars);
1105}
1106
1107/**
1108 * Displays a UNIX timestamp in a friendly way
1109 *
1110 * @see elgg_get_friendly_time()
1111 *
1112 * @param int $time A UNIX epoch timestamp
1113 *
1114 * @return string The friendly time HTML
1115 * @since 1.7.2
1116 */
1117function elgg_view_friendly_time($time) {
1118	return elgg_view('output/friendlytime', array('time' => $time));
1119}
1120
1121
1122/**
1123 * Returns rendered comments and a comment form for an entity.
1124 *
1125 * @tip Plugins can override the output by registering a handler
1126 * for the comments, $entity_type hook.  The handler is responsible
1127 * for formatting the comments and the add comment form.
1128 *
1129 * @param ElggEntity $entity      The entity to view comments of
1130 * @param bool       $add_comment Include a form to add comments?
1131 * @param array      $vars        Variables to pass to comment view
1132 *
1133 * @return string|false Rendered comments or false on failure
1134 * @link http://docs.elgg.org/Entities/Comments
1135 * @link http://docs.elgg.org/Annotations/Comments
1136 */
1137function elgg_view_comments($entity, $add_comment = true, array $vars = array()) {
1138	if (!($entity instanceof ElggEntity)) {
1139		return false;
1140	}
1141
1142	$vars['entity'] = $entity;
1143	$vars['show_add_form'] = $add_comment;
1144	$vars['class'] = elgg_extract('class', $vars, "{$entity->getSubtype()}-comments");
1145
1146	$output = elgg_trigger_plugin_hook('comments', $entity->getType(), $vars, false);
1147	if ($output) {
1148		return $output;
1149	} else {
1150		return elgg_view('page/elements/comments', $vars);
1151	}
1152}
1153
1154/**
1155 * Wrapper function for the image block display pattern.
1156 *
1157 * Fixed width media on the side (image, icon, flash, etc.).
1158 * Descriptive content filling the rest of the column.
1159 *
1160 * This is a shortcut for {@elgg_view page/components/image_block}.
1161 *
1162 * @param string $image The icon and other information
1163 * @param string $body  Description content
1164 * @param string $vars  Additional parameters for the view
1165 *
1166 * @return string
1167 * @since 1.8.0
1168 */
1169function elgg_view_image_block($image, $body, $vars = array()) {
1170	$vars['image'] = $image;
1171	$vars['body'] = $body;
1172	return elgg_view('page/components/image_block', $vars);
1173}
1174
1175/**
1176 * Wrapper function for the module display pattern.
1177 *
1178 * Box with header, body, footer
1179 *
1180 * This is a shortcut for {@elgg_view page/components/module}.
1181 *
1182 * @param string $type  The type of module (main, info, popup, aside, etc.)
1183 * @param string $title A title to put in the header
1184 * @param string $body  Content of the module
1185 * @param string $vars  Additional parameters for the module
1186 *
1187 * @return string
1188 * @since 1.8.0
1189 */
1190function elgg_view_module($type, $title, $body, $vars = array()) {
1191	$vars['class'] .= " elgg-module-$type"; //@todo this will probably cause errors?
1192	$vars['title'] = $title;
1193	$vars['body'] = $body;
1194	return elgg_view('page/components/module', $vars);
1195}
1196
1197/**
1198 * Renders a human-readable representation of a river item
1199 *
1200 * @param ElggRiverItem $item A river item object
1201 * @param array         $vars An array of variables for the view
1202 *
1203 * @return string|false Depending on success
1204 */
1205function elgg_view_river_item($item, array $vars = array()) {
1206	// checking default viewtype since some viewtypes do not have unique views per item (rss)
1207	if (!$item || !$item->getView() || !elgg_view_exists($item->getView(), 'default')) {
1208		return '';
1209	}
1210
1211	$subject = $item->getSubjectEntity();
1212	$object = $item->getObjectEntity();
1213	if (!$subject || !$object) {
1214		// subject is disabled or subject/object deleted
1215		return '';
1216	}
1217
1218	$vars['item'] = $item;
1219
1220	return elgg_view($item->getView(), $vars);
1221}
1222
1223/**
1224 * Convenience function for generating a form from a view in a standard location.
1225 *
1226 * This function assumes that the body of the form is located at "forms/$action" and
1227 * sets the action by default to "action/$action".  Automatically wraps the forms/$action
1228 * view with a <form> tag and inserts the anti-csrf security tokens.
1229 *
1230 * @tip This automatically appends elgg-form-action-name to the form's class. It replaces any
1231 * slashes with dashes (blog/save becomes elgg-form-blog-save)
1232 *
1233 * @example
1234 * <code>echo elgg_view_form('login');</code>
1235 *
1236 * This would assume a "login" form body to be at "forms/login" and would set the action
1237 * of the form to "http://yoursite.com/action/login".
1238 *
1239 * If elgg_view('forms/login') is:
1240 * <input type="text" name="username" />
1241 * <input type="password" name="password" />
1242 *
1243 * Then elgg_view_form('login') generates:
1244 * <form action="http://yoursite.com/action/login" method="post">
1245 *     ...security tokens...
1246 *     <input type="text" name="username" />
1247 *     <input type="password" name="password" />
1248 * </form>
1249 *
1250 * @param string $action    The name of the action. An action name does not include
1251 *                          the leading "action/". For example, "login" is an action name.
1252 * @param array  $form_vars $vars environment passed to the "input/form" view
1253 * @param array  $body_vars $vars environment passed to the "forms/$action" view
1254 *
1255 * @return string The complete form
1256 */
1257function elgg_view_form($action, $form_vars = array(), $body_vars = array()) {
1258	global $CONFIG;
1259
1260	$defaults = array(
1261		'action' => $CONFIG->wwwroot . "action/$action",
1262		'body' => elgg_view("forms/$action", $body_vars)
1263	);
1264
1265	$form_class = 'elgg-form-' . preg_replace('/[^a-z0-9]/i', '-', $action);
1266
1267	// append elgg-form class to any class options set
1268	if (isset($form_vars['class'])) {
1269		$form_vars['class'] = $form_vars['class'] . " $form_class";
1270	} else {
1271		$form_vars['class'] = $form_class;
1272	}
1273
1274	return elgg_view('input/form', array_merge($defaults, $form_vars));
1275}
1276
1277/**
1278 * View an item in a list
1279 *
1280 * @param object $item ElggEntity or ElggAnnotation
1281 * @param array  $vars Additional parameters for the rendering
1282 *
1283 * @return string
1284 * @since 1.8.0
1285 * @access private
1286 */
1287function elgg_view_list_item($item, array $vars = array()) {
1288
1289	switch ($item->getType()) {
1290		case 'user':
1291		case 'object':
1292		case 'group':
1293		case 'site':
1294			return elgg_view_entity($item, $vars);
1295		case 'annotation':
1296			return elgg_view_annotation($item, $vars);
1297		case 'river':
1298			return elgg_view_river_item($item, $vars);
1299		default:
1300			return false;
1301			break;
1302	}
1303}
1304
1305/**
1306 * View one of the elgg sprite icons
1307 * 
1308 * Shorthand for <span class="elgg-icon elgg-icon-$name"></span>
1309 * 
1310 * @param string $name  The specific icon to display
1311 * @param bool   $float Whether to float the icon
1312 * 
1313 * @return string The html for displaying an icon
1314 */
1315function elgg_view_icon($name, $float = false) {
1316	if ($float) {
1317		$float = 'float';
1318	}
1319	return "<span class=\"elgg-icon elgg-icon-$name $float\"></span>";
1320}
1321
1322/**
1323 * Registers a function to handle templates.
1324 *
1325 * Alternative template handlers can be registered to handle
1326 * all output functions.  By default, {@link elgg_view()} will
1327 * simply include the view file.  If an alternate template handler
1328 * is registered, the view name and passed $vars will be passed to the
1329 * registered function, which is then responsible for generating and returning
1330 * output.
1331 *
1332 * Template handlers need to accept two arguments: string $view_name and array
1333 * $vars.
1334 *
1335 * @warning This is experimental.
1336 *
1337 * @param string $function_name The name of the function to pass to.
1338 *
1339 * @return bool
1340 * @see elgg_view()
1341 * @link http://docs.elgg.org/Views/TemplateHandlers
1342 */
1343function set_template_handler($function_name) {
1344	global $CONFIG;
1345	if (!empty($function_name) && is_callable($function_name)) {
1346		$CONFIG->template_handler = $function_name;
1347		return true;
1348	}
1349	return false;
1350}
1351
1352/**
1353 * Returns the name of views for in a directory.
1354 *
1355 * Use this to get all namespaced views under the first element.
1356 *
1357 * @param string $dir  The main directory that holds the views. (mod/profile/views/)
1358 * @param string $base The root name of the view to use, without the viewtype. (profile)
1359 *
1360 * @return array
1361 * @since 1.7.0
1362 * @todo Why isn't this used anywhere else but in elgg_view_tree()?
1363 * Seems like a useful function for autodiscovery.
1364 */
1365function elgg_get_views($dir, $base) {
1366	$return = array();
1367	if (file_exists($dir) && is_dir($dir)) {
1368		if ($handle = opendir($dir)) {
1369			while ($view = readdir($handle)) {
1370				if (!in_array($view, array('.', '..', '.svn', 'CVS'))) {
1371					if (is_dir($dir . '/' . $view)) {
1372						if ($val = elgg_get_views($dir . '/' . $view, $base . '/' . $view)) {
1373							$return = array_merge($return, $val);
1374						}
1375					} else {
1376						$view = str_replace('.php', '', $view);
1377						$return[] = $base . '/' . $view;
1378					}
1379				}
1380			}
1381		}
1382	}
1383
1384	return $return;
1385}
1386
1387/**
1388 * Returns all views below a partial view.
1389 *
1390 * Settings $view_root = 'profile' will show all available views under
1391 * the "profile" namespace.
1392 *
1393 * @param string $view_root The root view
1394 * @param string $viewtype  Optionally specify a view type
1395 *                          other than the current one.
1396 *
1397 * @return array A list of view names underneath that root view
1398 * @todo This is used once in the deprecated get_activity_stream_data() function.
1399 */
1400function elgg_view_tree($view_root, $viewtype = "") {
1401	global $CONFIG;
1402	static $treecache;
1403
1404	// Get viewtype
1405	if (!$viewtype) {
1406		$viewtype = elgg_get_viewtype();
1407	}
1408
1409	// Has the treecache been initialised?
1410	if (!isset($treecache)) {
1411		$treecache = array();
1412	}
1413	// A little light internal caching
1414	if (!empty($treecache[$view_root])) {
1415		return $treecache[$view_root];
1416	}
1417
1418	// Examine $CONFIG->views->locations
1419	if (isset($CONFIG->views->locations[$viewtype])) {
1420		foreach ($CONFIG->views->locations[$viewtype] as $view => $path) {
1421			$pos = strpos($view, $view_root);
1422			if ($pos === 0) {
1423				$treecache[$view_root][] = $view;
1424			}
1425		}
1426	}
1427
1428	// Now examine core
1429	$location = $CONFIG->viewpath;
1430	$viewtype = elgg_get_viewtype();
1431	$root = $location . $viewtype . '/' . $view_root;
1432
1433	if (file_exists($root) && is_dir($root)) {
1434		$val = elgg_get_views($root, $view_root);
1435		if (!is_array($treecache[$view_root])) {
1436			$treecache[$view_root] = array();
1437		}
1438		$treecache[$view_root] = array_merge($treecache[$view_root], $val);
1439	}
1440
1441	return $treecache[$view_root];
1442}
1443
1444/**
1445 * Auto-registers views from a location.
1446 *
1447 * @note Views in plugin/views/ are automatically registered for active plugins.
1448 * Plugin authors would only need to call this if optionally including
1449 * an entire views structure.
1450 *
1451 * @param string $view_base          Optional The base of the view name without the view type.
1452 * @param string $folder             Required The folder to begin looking in
1453 * @param string $base_location_path The base views directory to use with elgg_set_view_location()
1454 * @param string $viewtype           The type of view we're looking at (default, rss, etc)
1455 *
1456 * @return void
1457 * @since 1.7.0
1458 * @see elgg_set_view_location()
1459 * @todo This seems overly complicated.
1460 */
1461function autoregister_views($view_base, $folder, $base_location_path, $viewtype) {
1462	if (!isset($i)) {
1463		$i = 0;
1464	}
1465
1466	if ($handle = opendir($folder)) {
1467		while ($view = readdir($handle)) {
1468			if (!in_array($view, array('.', '..', '.svn', 'CVS')) && !is_dir($folder . "/" . $view)) {
1469				// this includes png files because some icons are stored within view directories.
1470				// See commit [1705]
1471				if ((substr_count($view, ".php") > 0) || (substr_count($view, ".png") > 0)) {
1472					if (!empty($view_base)) {
1473						$view_base_new = $view_base . "/";
1474					} else {
1475						$view_base_new = "";
1476					}
1477
1478					elgg_set_view_location($view_base_new . str_replace('.php', '', $view),
1479						$base_location_path, $viewtype);
1480				}
1481			} else if (!in_array($view, array('.', '..', '.svn', 'CVS')) && is_dir($folder . "/" . $view)) {
1482				if (!empty($view_base)) {
1483					$view_base_new = $view_base . "/";
1484				} else {
1485					$view_base_new = "";
1486				}
1487				autoregister_views($view_base_new . $view, $folder . "/" . $view,
1488					$base_location_path, $viewtype);
1489			}
1490		}
1491		return TRUE;
1492	}
1493
1494	return FALSE;
1495}
1496
1497/**
1498 * Add the rss link to the extras when if needed
1499 *
1500 * @return void
1501 */
1502function elgg_views_add_rss_link() {
1503	global $autofeed;
1504	if (isset($autofeed) && $autofeed == true) {
1505		$url = full_url();
1506		if (substr_count($url, '?')) {
1507			$url .= "&view=rss";
1508		} else {
1509			$url .= "?view=rss";
1510		}
1511
1512		$url = elgg_format_url($url);
1513		elgg_register_menu_item('extras', array(
1514			'name' => 'rss',
1515			'text' => elgg_view_icon('rss'),
1516			'href' => $url,
1517			'title' => elgg_echo('feed:rss'),
1518		));
1519	}
1520}
1521
1522/**
1523 * Registers deprecated views to avoid making some pages from older plugins
1524 * completely empty.
1525 *
1526 * @private
1527 */
1528function elgg_views_handle_deprecated_views() {
1529	$location = elgg_get_view_location('page_elements/contentwrapper');
1530	if ($location === "/var/www/views/") {
1531		elgg_extend_view('page_elements/contentwrapper', 'page/elements/wrapper');
1532	}
1533}
1534
1535/**
1536 * Initialize viewtypes on system boot event
1537 * This ensures simplecache is cleared during upgrades. See #2252
1538 *
1539 * @return void
1540 * @access private
1541 * @elgg_event_handler boot system
1542 */
1543function elgg_views_boot() {
1544	global $CONFIG;
1545
1546	elgg_register_simplecache_view('css/elgg');
1547	elgg_register_simplecache_view('css/ie');
1548	elgg_register_simplecache_view('css/ie6');
1549	elgg_register_simplecache_view('js/elgg');
1550
1551	elgg_register_js('jquery', '/vendors/jquery/jquery-1.6.2.min.js', 'head');
1552	elgg_register_js('jquery-ui', '/vendors/jquery/jquery-ui-1.8.16.min.js', 'head');
1553	elgg_register_js('jquery.form', '/vendors/jquery/jquery.form.js');
1554	
1555	$elgg_js_url = elgg_get_simplecache_url('js', 'elgg');
1556	elgg_register_js('elgg', $elgg_js_url, 'head');
1557
1558	elgg_load_js('jquery');
1559	elgg_load_js('jquery-ui');
1560	elgg_load_js('jquery.form');
1561	elgg_load_js('elgg');
1562
1563	elgg_register_simplecache_view('js/lightbox');
1564	$lightbox_js_url = elgg_get_simplecache_url('js', 'lightbox');
1565	elgg_register_js('lightbox', $lightbox_js_url);
1566	$lightbox_css_url = elgg_get_simplecache_url('css', 'lightbox');
1567	elgg_register_css('lightbox', $lightbox_css_url);
1568
1569	$elgg_css_url = elgg_get_simplecache_url('css', 'elgg');
1570	elgg_register_css('elgg', $elgg_css_url, 1);
1571	elgg_load_css('elgg');
1572
1573	elgg_register_plugin_hook_handler('output:before', 'layout', 'elgg_views_add_rss_link');
1574
1575	// discover the built-in view types
1576	// @todo the cache is loaded in load_plugins() but we need to know view_types earlier
1577	$view_path = $CONFIG->viewpath;
1578
1579	$views = scandir($view_path);
1580
1581	foreach ($views as $view) {
1582		if ('.' !== substr($view, 0, 1) && is_dir($view_path . $view)) {
1583			elgg_register_viewtype($view);
1584		}
1585	}
1586}
1587
1588elgg_register_event_handler('boot', 'system', 'elgg_views_boot', 1000);
1589elgg_register_event_handler('init', 'system', 'elgg_views_handle_deprecated_views');