These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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 | * Viewtypes are set by passing $_REQUEST['view']. The viewtype |
||
36 | * 'default' is a standard HTML view. Types can be defined on the fly |
||
37 | * and you can get the current viewtype with {@link elgg_get_viewtype()}. |
||
38 | * |
||
39 | * @note Internal: Plugin views are autoregistered before their init functions |
||
40 | * are called, so the init order doesn't affect views. |
||
41 | * |
||
42 | * @note 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 | */ |
||
48 | |||
49 | use Elgg\Menu\Menu; |
||
50 | use Elgg\Menu\UnpreparedMenu; |
||
51 | use Elgg\Includer; |
||
52 | |||
53 | /** |
||
54 | * Manually set the viewtype. |
||
55 | * |
||
56 | * View types are detected automatically. This function allows |
||
57 | * you to force subsequent views to use a different viewtype. |
||
58 | * |
||
59 | * @tip Call elgg_set_viewtype() with no parameter to reset. |
||
60 | * |
||
61 | * @param string $viewtype The view type, e.g. 'rss', or 'default'. |
||
62 | * |
||
63 | * @return bool |
||
64 | */ |
||
65 | function elgg_set_viewtype($viewtype = '') { |
||
66 | 7 | return _elgg_services()->views->setViewtype($viewtype); |
|
67 | } |
||
68 | |||
69 | /** |
||
70 | * Return the current view type. |
||
71 | * |
||
72 | * Viewtypes are automatically detected and can be set with $_REQUEST['view'] |
||
73 | * or {@link elgg_set_viewtype()}. |
||
74 | * |
||
75 | * @return string The viewtype |
||
76 | * @see elgg_set_viewtype() |
||
77 | */ |
||
78 | function elgg_get_viewtype() { |
||
79 | 11 | return _elgg_services()->views->getViewtype(); |
|
80 | } |
||
81 | |||
82 | /** |
||
83 | * Checks if $viewtype is a string suitable for use as a viewtype name |
||
84 | * |
||
85 | * @param string $viewtype Potential viewtype name. Alphanumeric chars plus _ allowed. |
||
86 | * |
||
87 | * @return bool |
||
88 | * @access private |
||
89 | * @since 1.9 |
||
90 | */ |
||
91 | function _elgg_is_valid_viewtype($viewtype) { |
||
92 | 1 | return _elgg_services()->views->isValidViewtype($viewtype); |
|
93 | } |
||
94 | |||
95 | /** |
||
96 | * Register a viewtype to fall back to a default view if a view isn't |
||
97 | * found for that viewtype. |
||
98 | * |
||
99 | * @tip This is useful for alternate html viewtypes (such as for mobile devices). |
||
100 | * |
||
101 | * @param string $viewtype The viewtype to register |
||
102 | * |
||
103 | * @return void |
||
104 | * @since 1.7.2 |
||
105 | */ |
||
106 | function elgg_register_viewtype_fallback($viewtype) { |
||
107 | _elgg_services()->views->registerViewtypeFallback($viewtype); |
||
108 | } |
||
109 | |||
110 | /** |
||
111 | * Checks if a viewtype falls back to default. |
||
112 | * |
||
113 | * @param string $viewtype Viewtype |
||
114 | * |
||
115 | * @return boolean |
||
116 | * @since 1.7.2 |
||
117 | */ |
||
118 | function elgg_does_viewtype_fallback($viewtype) { |
||
119 | return _elgg_services()->views->doesViewtypeFallback($viewtype); |
||
120 | } |
||
121 | |||
122 | /** |
||
123 | * Register a view to be available for ajax calls |
||
124 | * |
||
125 | * @warning Only views that begin with 'js/' and 'css/' have their content |
||
126 | * type set to 'text/javascript' and 'text/css'. Other views are served as |
||
127 | * 'text/html'. |
||
128 | * |
||
129 | * @param string $view The view name |
||
130 | * @return void |
||
131 | * @since 1.8.3 |
||
132 | */ |
||
133 | function elgg_register_ajax_view($view) { |
||
134 | 9 | elgg_register_external_view($view, false); |
|
135 | 9 | } |
|
136 | |||
137 | /** |
||
138 | * Unregister a view for ajax calls |
||
139 | * |
||
140 | * @param string $view The view name |
||
141 | * @return void |
||
142 | * @since 1.8.3 |
||
143 | */ |
||
144 | function elgg_unregister_ajax_view($view) { |
||
145 | elgg_unregister_external_view($view); |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Registers a view as being available externally (i.e. via URL). |
||
150 | * |
||
151 | * @param string $view The name of the view. |
||
152 | * @param boolean $cacheable Whether this view can be cached. |
||
153 | * @return void |
||
154 | * @since 1.9.0 |
||
155 | */ |
||
156 | function elgg_register_external_view($view, $cacheable = false) { |
||
157 | |||
158 | 9 | _elgg_services()->ajax->registerView($view); |
|
159 | |||
160 | 9 | if ($cacheable) { |
|
161 | _elgg_services()->views->registerCacheableView($view); |
||
162 | } |
||
163 | 9 | } |
|
164 | |||
165 | /** |
||
166 | * Unregister a view for ajax calls |
||
167 | * |
||
168 | * @param string $view The view name |
||
169 | * @return void |
||
170 | * @since 1.9.0 |
||
171 | */ |
||
172 | function elgg_unregister_external_view($view) { |
||
173 | _elgg_services()->ajax->unregisterView($view); |
||
174 | } |
||
175 | |||
176 | /** |
||
177 | * Set an alternative base location for a view. |
||
178 | * |
||
179 | * Views are expected to be in plugin_name/views/. This function can |
||
180 | * be used to change that location. |
||
181 | * |
||
182 | * @tip This is useful to optionally register views in a plugin. |
||
183 | * |
||
184 | * @param string $view The name of the view |
||
185 | * @param string $location The full path to the view |
||
186 | * @param string $viewtype The view type |
||
187 | * |
||
188 | * @return void |
||
189 | */ |
||
190 | function elgg_set_view_location($view, $location, $viewtype = '') { |
||
191 | _elgg_services()->views->setViewDir($view, $location, $viewtype); |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Returns whether the specified view exists |
||
196 | * |
||
197 | * @note If $recurse is true, also checks if a view exists only as an extension. |
||
198 | * |
||
199 | * @param string $view The view name |
||
200 | * @param string $viewtype If set, forces the viewtype |
||
201 | * @param bool $recurse If false, do not check extensions |
||
202 | * |
||
203 | * @return bool |
||
204 | */ |
||
205 | function elgg_view_exists($view, $viewtype = '', $recurse = true) { |
||
206 | 5 | return _elgg_services()->views->viewExists($view, $viewtype, $recurse); |
|
207 | } |
||
208 | |||
209 | /** |
||
210 | * List all views in a viewtype |
||
211 | * |
||
212 | * @param string $viewtype Viewtype |
||
213 | * |
||
214 | * @return string[] |
||
215 | * |
||
216 | * @since 2.0 |
||
217 | */ |
||
218 | function elgg_list_views($viewtype = 'default') { |
||
219 | return _elgg_services()->views->listViews($viewtype); |
||
220 | } |
||
221 | |||
222 | /** |
||
223 | * Return a parsed view. |
||
224 | * |
||
225 | * Views are rendered by a template handler and returned as strings. |
||
226 | * |
||
227 | * Views are called with a special $vars variable set, |
||
228 | * which includes any variables passed as the second parameter. |
||
229 | * |
||
230 | * The input of views can be intercepted by registering for the |
||
231 | * view_vars, $view_name plugin hook. |
||
232 | * |
||
233 | * If the input contains the key "__view_output", the view will output this value as a string. |
||
234 | * No extensions are used, and the "view" hook is not triggered). |
||
235 | * |
||
236 | * The output of views can be intercepted by registering for the |
||
237 | * view, $view_name plugin hook. |
||
238 | * |
||
239 | * @param string $view The name and location of the view to use |
||
240 | * @param array $vars Variables to pass to the view. |
||
241 | * @param string $viewtype If set, forces the viewtype for the elgg_view call to be |
||
242 | * this value (default: standard detection) |
||
243 | * |
||
244 | * @return string The parsed view |
||
245 | */ |
||
246 | function elgg_view($view, $vars = [], $viewtype = '') { |
||
247 | 21 | if (func_num_args() == 5) { |
|
248 | elgg_log(__FUNCTION__ . ' now has only 3 arguments. Update your usage.', 'ERROR'); |
||
249 | $viewtype = func_get_arg(4); |
||
250 | } |
||
251 | 21 | return _elgg_services()->views->renderView($view, $vars, $viewtype); |
|
252 | } |
||
253 | |||
254 | /** |
||
255 | * Display a view with a deprecation notice. No missing view NOTICE is logged |
||
256 | * |
||
257 | * @see elgg_view() |
||
258 | * |
||
259 | * @param string $view The name and location of the view to use |
||
260 | * @param array $vars Variables to pass to the view |
||
261 | * @param string $suggestion Suggestion with the deprecation message |
||
262 | * @param string $version Human-readable *release* version: 1.7, 1.8, ... |
||
263 | * |
||
264 | * @return string The parsed view |
||
265 | * @access private |
||
266 | */ |
||
267 | function elgg_view_deprecated($view, array $vars, $suggestion, $version) { |
||
268 | return _elgg_services()->views->renderDeprecatedView($view, $vars, $suggestion, $version); |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * Extends a view with another view. |
||
273 | * |
||
274 | * The output of any view can be prepended or appended to any other view. |
||
275 | * |
||
276 | * The default action is to append a view. If the priority is less than 500, |
||
277 | * the output of the extended view will be appended to the original view. |
||
278 | * |
||
279 | * Views can be extended multiple times, and extensions are not checked for |
||
280 | * uniqueness. Use {@link elgg_unextend_view()} to help manage duplicates. |
||
281 | * |
||
282 | * Priority can be specified and affects the order in which extensions |
||
283 | * are appended or prepended. |
||
284 | * |
||
285 | * @see elgg_prepend_css_urls() If the extension is CSS, you may need to use this to fix relative URLs. |
||
286 | * |
||
287 | * @param string $view The view to extend. |
||
288 | * @param string $view_extension This view is added to $view |
||
289 | * @param int $priority The priority, from 0 to 1000, to add at (lowest numbers displayed first) |
||
290 | * |
||
291 | * @return void |
||
292 | * @since 1.7.0 |
||
293 | */ |
||
294 | function elgg_extend_view($view, $view_extension, $priority = 501) { |
||
295 | _elgg_services()->views->extendView($view, $view_extension, $priority); |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * Unextends a view. |
||
300 | * |
||
301 | * @param string $view The view that was extended. |
||
302 | * @param string $view_extension This view that was added to $view |
||
303 | * |
||
304 | * @return bool |
||
305 | * @since 1.7.2 |
||
306 | */ |
||
307 | function elgg_unextend_view($view, $view_extension) { |
||
308 | return _elgg_services()->views->unextendView($view, $view_extension); |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * Get the views (and priorities) that extend a view. |
||
313 | * |
||
314 | * @note extensions may change anytime, especially during the [init, system] event |
||
315 | * |
||
316 | * @param string $view View name |
||
317 | * |
||
318 | * @return string[] Keys returned are view priorities. |
||
319 | * @since 2.3 |
||
320 | */ |
||
321 | function elgg_get_view_extensions($view) { |
||
322 | $list = _elgg_services()->views->getViewList($view); |
||
323 | unset($list[500]); |
||
324 | return $list; |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * In CSS content, prepend a path to relative URLs. |
||
329 | * |
||
330 | * This is useful to process a CSS view being used as an extension. |
||
331 | * |
||
332 | * @param string $css CSS |
||
333 | * @param string $path Path to prepend. E.g. "foo/bar/" or "../" |
||
334 | * |
||
335 | * @return string |
||
336 | * @since 2.2 |
||
337 | */ |
||
338 | function elgg_prepend_css_urls($css, $path) { |
||
339 | 1 | return Minify_CSS_UriRewriter::prepend($css, $path); |
|
340 | } |
||
341 | |||
342 | /** |
||
343 | * Assembles and outputs a full page. |
||
344 | * |
||
345 | * A "page" in Elgg is determined by the current view type and |
||
346 | * can be HTML for a browser, RSS for a feed reader, or |
||
347 | * Javascript, PHP and a number of other formats. |
||
348 | * |
||
349 | * For HTML pages, use the 'head', 'page' plugin hook for setting meta elements |
||
350 | * and links. |
||
351 | * |
||
352 | * @param string $title Title |
||
353 | * @param string $body Body |
||
354 | * @param string $page_shell Optional page shell to use. See page/shells view directory |
||
355 | * @param array $vars Optional vars array to pass to the page |
||
356 | * shell. Automatically adds title, body, head, and sysmessages |
||
357 | * |
||
358 | * @return string The contents of the page |
||
359 | * @since 1.8 |
||
360 | */ |
||
361 | function elgg_view_page($title, $body, $page_shell = 'default', $vars = []) { |
||
362 | 4 | $timer = _elgg_services()->timer; |
|
363 | 4 | if (!$timer->hasEnded(['build page'])) { |
|
364 | 1 | $timer->end(['build page']); |
|
365 | } |
||
366 | 4 | $timer->begin([__FUNCTION__]); |
|
367 | |||
368 | 4 | $params = []; |
|
369 | 4 | $params['identifier'] = _elgg_services()->request->getFirstUrlSegment(); |
|
370 | 4 | $params['segments'] = _elgg_services()->request->getUrlSegments(); |
|
371 | 4 | array_shift($params['segments']); |
|
372 | 4 | $page_shell = elgg_trigger_plugin_hook('shell', 'page', $params, $page_shell); |
|
373 | |||
374 | |||
375 | 4 | $system_messages = _elgg_services()->systemMessages; |
|
376 | |||
377 | 4 | $messages = null; |
|
378 | 4 | if ($system_messages->count()) { |
|
379 | $messages = $system_messages->dumpRegister(); |
||
380 | |||
381 | if (isset($messages['error'])) { |
||
382 | // always make sure error is the first type |
||
383 | $errors = [ |
||
384 | 'error' => $messages['error'] |
||
385 | ]; |
||
386 | |||
387 | unset($messages['error']); |
||
388 | $messages = array_merge($errors, $messages); |
||
389 | } |
||
390 | } |
||
391 | |||
392 | 4 | $vars['title'] = $title; |
|
393 | 4 | $vars['body'] = $body; |
|
394 | 4 | $vars['sysmessages'] = $messages; |
|
395 | 4 | $vars['admin_notices'] = elgg_is_admin_logged_in() ? elgg_get_admin_notices() : []; |
|
396 | 4 | $vars['page_shell'] = $page_shell; |
|
397 | |||
398 | // head has keys 'title', 'metas', 'links' |
||
399 | 4 | $head_params = _elgg_views_prepare_head($title); |
|
400 | |||
401 | 4 | $vars['head'] = elgg_trigger_plugin_hook('head', 'page', $vars, $head_params); |
|
402 | |||
403 | 4 | $vars = elgg_trigger_plugin_hook('output:before', 'page', null, $vars); |
|
404 | |||
405 | 4 | $output = elgg_view("page/$page_shell", $vars); |
|
406 | |||
407 | |||
408 | // Allow plugins to modify the output |
||
409 | 4 | $output = elgg_trigger_plugin_hook('output', 'page', $vars, $output); |
|
410 | |||
411 | 4 | $timer->end([__FUNCTION__]); |
|
412 | 4 | return $output; |
|
413 | } |
||
414 | |||
415 | /** |
||
416 | * Render a resource view. Use this in your page handler to hand off page rendering to |
||
417 | * a view in "resources/". If not found in the current viewtype, we try the "default" viewtype. |
||
418 | * |
||
419 | * @param string $name The view name without the leading "resources/" |
||
420 | * @param array $vars Arguments passed to the view |
||
421 | * |
||
422 | * @return string |
||
423 | * @throws SecurityException |
||
424 | */ |
||
425 | function elgg_view_resource($name, array $vars = []) { |
||
426 | 4 | $view = "resources/$name"; |
|
427 | |||
428 | 4 | if (elgg_view_exists($view)) { |
|
429 | 4 | return _elgg_services()->views->renderView($view, $vars); |
|
430 | } |
||
431 | |||
432 | if (elgg_get_viewtype() !== 'default' && elgg_view_exists($view, 'default')) { |
||
433 | return _elgg_services()->views->renderView($view, $vars, 'default'); |
||
434 | } |
||
435 | |||
436 | _elgg_services()->logger->error("The view $view is missing."); |
||
437 | |||
438 | if (elgg_get_viewtype() === 'default') { |
||
439 | // only works for default viewtype |
||
440 | forward('', '404'); |
||
441 | } else { |
||
442 | register_error(elgg_echo('error:404:content')); |
||
443 | forward(''); |
||
444 | } |
||
445 | } |
||
446 | |||
447 | /** |
||
448 | * Prepare the variables for the html head |
||
449 | * |
||
450 | * @param string $title Page title for <head> |
||
451 | * @return array |
||
452 | * @access private |
||
453 | */ |
||
454 | function _elgg_views_prepare_head($title) { |
||
455 | $params = [ |
||
456 | 4 | 'links' => [], |
|
457 | 'metas' => [], |
||
458 | ]; |
||
459 | |||
460 | 4 | if (empty($title)) { |
|
461 | $params['title'] = _elgg_config()->sitename; |
||
462 | } else { |
||
463 | 4 | $params['title'] = $title . ' : ' . _elgg_config()->sitename; |
|
464 | } |
||
465 | |||
466 | 4 | $params['metas']['content-type'] = [ |
|
467 | 'http-equiv' => 'Content-Type', |
||
468 | 'content' => 'text/html; charset=utf-8', |
||
469 | ]; |
||
470 | |||
471 | 4 | $params['metas']['description'] = [ |
|
472 | 4 | 'name' => 'description', |
|
473 | 4 | 'content' => _elgg_config()->sitedescription |
|
474 | ]; |
||
475 | |||
476 | // https://developer.chrome.com/multidevice/android/installtohomescreen |
||
477 | 4 | $params['metas']['viewport'] = [ |
|
478 | 'name' => 'viewport', |
||
479 | 'content' => 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0', |
||
480 | ]; |
||
481 | 4 | $params['metas']['mobile-web-app-capable'] = [ |
|
482 | 'name' => 'mobile-web-app-capable', |
||
483 | 'content' => 'yes', |
||
484 | ]; |
||
485 | 4 | $params['metas']['apple-mobile-web-app-capable'] = [ |
|
486 | 'name' => 'apple-mobile-web-app-capable', |
||
487 | 'content' => 'yes', |
||
488 | ]; |
||
489 | |||
490 | // RSS feed link |
||
491 | 4 | if (_elgg_has_rss_link()) { |
|
492 | $url = current_page_url(); |
||
493 | if (substr_count($url, '?')) { |
||
494 | $url .= "&view=rss"; |
||
495 | } else { |
||
496 | $url .= "?view=rss"; |
||
497 | } |
||
498 | $params['links']['rss'] = [ |
||
499 | 'rel' => 'alternative', |
||
500 | 'type' => 'application/rss+xml', |
||
501 | 'title' => 'RSS', |
||
502 | 'href' => $url, |
||
503 | ]; |
||
504 | } |
||
505 | |||
506 | 4 | return $params; |
|
507 | } |
||
508 | |||
509 | |||
510 | /** |
||
511 | * Add favicon link tags to HTML head |
||
512 | * |
||
513 | * @param string $hook "head" |
||
514 | * @param string $type "page" |
||
515 | * @param array $head_params Head params |
||
516 | * <code> |
||
517 | * [ |
||
518 | * 'title' => '', |
||
519 | * 'metas' => [], |
||
520 | * 'links' => [], |
||
521 | * ] |
||
522 | * </code> |
||
523 | * @param array $params Hook params |
||
524 | * @return array |
||
525 | */ |
||
526 | function _elgg_views_prepare_favicon_links($hook, $type, $head_params, $params) { |
||
527 | |||
528 | $head_params['links']['apple-touch-icon'] = [ |
||
529 | 'rel' => 'apple-touch-icon', |
||
530 | 'href' => elgg_get_simplecache_url('graphics/favicon-128.png'), |
||
531 | ]; |
||
532 | |||
533 | // favicons |
||
534 | $head_params['links']['icon-ico'] = [ |
||
535 | 'rel' => 'icon', |
||
536 | 'href' => elgg_get_simplecache_url('graphics/favicon.ico'), |
||
537 | ]; |
||
538 | $head_params['links']['icon-vector'] = [ |
||
539 | 'rel' => 'icon', |
||
540 | 'sizes' => '16x16 32x32 48x48 64x64 128x128', |
||
541 | 'type' => 'image/svg+xml', |
||
542 | 'href' => elgg_get_simplecache_url('graphics/favicon.svg'), |
||
543 | ]; |
||
544 | $head_params['links']['icon-16'] = [ |
||
545 | 'rel' => 'icon', |
||
546 | 'sizes' => '16x16', |
||
547 | 'type' => 'image/png', |
||
548 | 'href' => elgg_get_simplecache_url('graphics/favicon-16.png'), |
||
549 | ]; |
||
550 | $head_params['links']['icon-32'] = [ |
||
551 | 'rel' => 'icon', |
||
552 | 'sizes' => '32x32', |
||
553 | 'type' => 'image/png', |
||
554 | 'href' => elgg_get_simplecache_url('graphics/favicon-32.png'), |
||
555 | ]; |
||
556 | $head_params['links']['icon-64'] = [ |
||
557 | 'rel' => 'icon', |
||
558 | 'sizes' => '64x64', |
||
559 | 'type' => 'image/png', |
||
560 | 'href' => elgg_get_simplecache_url('graphics/favicon-64.png'), |
||
561 | ]; |
||
562 | $head_params['links']['icon-128'] = [ |
||
563 | 'rel' => 'icon', |
||
564 | 'sizes' => '128x128', |
||
565 | 'type' => 'image/png', |
||
566 | 'href' => elgg_get_simplecache_url('graphics/favicon-128.png'), |
||
567 | ]; |
||
568 | |||
569 | return $head_params; |
||
570 | } |
||
571 | |||
572 | /** |
||
573 | * Displays a layout with optional parameters. |
||
574 | * |
||
575 | * Layouts are templates provide consistency by organizing blocks of content on the page. |
||
576 | * |
||
577 | * Plugins should use one of the core layouts: |
||
578 | * - default Primary template with one, two or no sidebars |
||
579 | * - admin Admin page template |
||
580 | * - error Error page template |
||
581 | * - widgets Widgets canvas |
||
582 | * |
||
583 | * Plugins can create and use custom layouts by placing a layout view |
||
584 | * in "page/layouts/<layout_name>" and calling elgg_view_layout(<layout_name>). |
||
585 | * |
||
586 | * For a full list of parameters supported by each of these layouts see |
||
587 | * corresponding layout views. |
||
588 | * |
||
589 | * @param string $layout_name Layout name |
||
590 | * Corresponds to a view in "page/layouts/<layout_name>". |
||
591 | * @param array $vars Layout parameters |
||
592 | * An associative array of parameters to pass to |
||
593 | * the layout hooks and views. |
||
594 | * Route 'identifier' and 'segments' of the page being |
||
595 | * rendered will be added to this array automatially, |
||
596 | * allowing plugins to alter layout views and subviews |
||
597 | * based on the current route. |
||
598 | * @return string |
||
599 | */ |
||
600 | function elgg_view_layout($layout_name, $vars = []) { |
||
601 | $timer = _elgg_services()->timer; |
||
602 | if (!$timer->hasEnded(['build page'])) { |
||
603 | $timer->end(['build page']); |
||
604 | } |
||
605 | $timer->begin([__FUNCTION__]); |
||
606 | |||
607 | // Help plugins transition without breaking them |
||
608 | switch ($layout_name) { |
||
609 | case 'content' : |
||
610 | $layout_name = 'default'; |
||
611 | $vars = _elgg_normalize_content_layout_vars($vars); |
||
612 | break; |
||
613 | |||
614 | View Code Duplication | case 'one_sidebar' : |
|
615 | $layout_name = 'default'; |
||
616 | $vars['sidebar'] = elgg_extract('sidebar', $vars, '', false); |
||
617 | $vars['sidebar_alt'] = false; |
||
618 | break; |
||
619 | |||
620 | case 'one_column' : |
||
621 | $layout_name = 'default'; |
||
622 | $vars['sidebar'] = false; |
||
623 | $vars['sidebar_alt'] = false; |
||
624 | break; |
||
625 | |||
626 | View Code Duplication | case 'two_sidebar' : |
|
627 | $layout_name = 'default'; |
||
628 | $vars['sidebar'] = elgg_extract('sidebar', $vars, '', false); |
||
629 | $vars['sidebar_alt'] = elgg_extract('sidebar_alt', $vars, '', false); |
||
630 | break; |
||
631 | } |
||
632 | |||
633 | if (isset($vars['nav'])) { |
||
634 | // Temporary helper until all core views are updated |
||
635 | $vars['breadcrumbs'] = $vars['nav']; |
||
636 | unset($vars['nav']); |
||
637 | } |
||
638 | |||
639 | $vars['identifier'] = _elgg_services()->request->getFirstUrlSegment(); |
||
640 | $vars['segments'] = _elgg_services()->request->getUrlSegments(); |
||
641 | array_shift($vars['segments']); |
||
642 | |||
643 | $layout_name = elgg_trigger_plugin_hook('layout', 'page', $vars, $layout_name); |
||
644 | |||
645 | $vars['layout'] = $layout_name; |
||
646 | |||
647 | $layout_views = [ |
||
648 | "page/layouts/$layout_name", |
||
649 | "page/layouts/default", |
||
650 | ]; |
||
651 | |||
652 | $output = ''; |
||
653 | foreach ($layout_views as $layout_view) { |
||
654 | if (elgg_view_exists($layout_view)) { |
||
655 | $output = elgg_view($layout_view, $vars); |
||
656 | break; |
||
657 | } |
||
658 | } |
||
659 | |||
660 | $timer->end([__FUNCTION__]); |
||
661 | return $output; |
||
662 | } |
||
663 | |||
664 | /** |
||
665 | * Normalizes deprecated content layout $vars for use in default layout |
||
666 | * Helper function to assist plugins transitioning to 3.0 |
||
667 | * |
||
668 | * @param array $vars Vars |
||
669 | * @return array |
||
670 | * @access private |
||
671 | */ |
||
672 | function _elgg_normalize_content_layout_vars(array $vars = []) { |
||
673 | |||
674 | $context = elgg_extract('context', $vars, elgg_get_context()); |
||
675 | |||
676 | $vars['title'] = elgg_extract('title', $vars, ''); |
||
677 | if (!$vars['title'] && $vars['title'] !== false) { |
||
678 | $vars['title'] = elgg_echo($context); |
||
679 | } |
||
680 | |||
681 | // 1.8 supported 'filter_override' |
||
682 | if (isset($vars['filter_override'])) { |
||
683 | $vars['filter'] = $vars['filter_override']; |
||
684 | } |
||
685 | |||
686 | // register the default content filters |
||
687 | if (!isset($vars['filter']) && $context) { |
||
688 | $selected = elgg_extract('filter_context', $vars); |
||
689 | $vars['filter'] = elgg_get_filter_tabs($context, $selected, null, $vars); |
||
690 | $vars['filter_id'] = $context; |
||
691 | $vars['filter_value'] = $selected; |
||
692 | } |
||
693 | |||
694 | return $vars; |
||
695 | } |
||
696 | |||
697 | /** |
||
698 | * Render a menu |
||
699 | * |
||
700 | * @see elgg_register_menu_item() for documentation on adding menu items and |
||
701 | * navigation.php for information on the different menus available. |
||
702 | * |
||
703 | * This function triggers a 'register', 'menu:<menu name>' plugin hook that enables |
||
704 | * plugins to add menu items just before a menu is rendered. This is used by |
||
705 | * dynamic menus (menus that change based on some input such as the user hover |
||
706 | * menu). Using elgg_register_menu_item() in response to the hook can cause |
||
707 | * incorrect links to show up. See the blog plugin's blog_owner_block_menu() |
||
708 | * for an example of using this plugin hook. |
||
709 | * |
||
710 | * An additional hook is the 'prepare', 'menu:<menu name>' which enables plugins |
||
711 | * to modify the structure of the menu (sort it, remove items, set variables on |
||
712 | * the menu items). |
||
713 | * |
||
714 | * Preset (unprepared) menu items passed to the this function with the $vars |
||
715 | * argument, will be merged with the registered items (registered with |
||
716 | * elgg_register_menu_item()). The combined set of menu items will be passed |
||
717 | * to 'register', 'menu:<menu_name>' hook. |
||
718 | * |
||
719 | * Plugins that pass preset menu items to this function and do not wish to be |
||
720 | * affected by plugin hooks (e.g. if you are displaying multiple menus with |
||
721 | * the same name on the page) should instead choose a unqie menu name |
||
722 | * and define a menu_view argument to render menus consistently. |
||
723 | * For example, if you have multiple 'filter' menus on the page: |
||
724 | * <code> |
||
725 | * elgg_view_menu("filter:$uid", [ |
||
726 | * 'items' => $items, |
||
727 | * 'menu_view' => 'navigation/menu/filter', |
||
728 | * ]); |
||
729 | * </code> |
||
730 | * |
||
731 | * elgg_view_menu() uses views in navigation/menu |
||
732 | * |
||
733 | * @param string|Menu|UnpreparedMenu $menu Menu name (or object) |
||
734 | * @param array $vars An associative array of display options for the menu. |
||
735 | * |
||
736 | * Options include: |
||
737 | * items => an array of unprepared menu items |
||
738 | * as ElggMenuItem or menu item factory options |
||
739 | * sort_by => string or php callback |
||
740 | * string options: 'name', 'priority', 'title' (default), |
||
741 | * 'register' (registration order) or a |
||
742 | * php callback (a compare function for usort) |
||
743 | * handler: string the page handler to build action URLs |
||
744 | * entity: \ElggEntity to use to build action URLs |
||
745 | * class: string the class for the entire menu. |
||
746 | * menu_view: name of the view to be used to render the menu |
||
747 | * show_section_headers: bool show headers before menu sections. |
||
748 | * |
||
749 | * @return string |
||
750 | * @since 1.8.0 |
||
751 | */ |
||
752 | function elgg_view_menu($menu, array $vars = []) { |
||
753 | |||
754 | $menu_view = elgg_extract('menu_view', $vars); |
||
755 | unset($vars['menu_view']); |
||
756 | |||
757 | if (is_string($menu)) { |
||
758 | $menu = _elgg_services()->menus->getMenu($menu, $vars); |
||
759 | } elseif ($menu instanceof UnpreparedMenu) { |
||
760 | $menu = _elgg_services()->menus->prepareMenu($menu); |
||
761 | } |
||
762 | |||
763 | if (!$menu instanceof Menu) { |
||
764 | throw new \InvalidArgumentException('$menu must be a menu name, a Menu, or UnpreparedMenu'); |
||
765 | } |
||
766 | |||
767 | $name = $menu->getName(); |
||
768 | $params = $menu->getParams(); |
||
769 | |||
770 | $views = [ |
||
771 | $menu_view, |
||
772 | "navigation/menu/$name", |
||
773 | 'navigation/menu/default', |
||
774 | ]; |
||
775 | |||
776 | foreach ($views as $view) { |
||
777 | if (elgg_view_exists($view)) { |
||
778 | return elgg_view($view, $params); |
||
779 | } |
||
780 | } |
||
781 | } |
||
782 | |||
783 | /** |
||
784 | * Render a menu item (usually as a link) |
||
785 | * |
||
786 | * @param \ElggMenuItem $item The menu item |
||
787 | * @param array $vars Options to pass to output/url if a link |
||
788 | * @return string |
||
789 | * @since 1.9.0 |
||
790 | */ |
||
791 | function elgg_view_menu_item(\ElggMenuItem $item, array $vars = []) { |
||
792 | |||
793 | $vars = array_merge($item->getValues(), $vars); |
||
794 | $vars['class'] = elgg_extract_class($vars, ['elgg-menu-content']); |
||
795 | |||
796 | if ($item->getLinkClass()) { |
||
797 | $vars['class'][] = $item->getLinkClass(); |
||
798 | } |
||
799 | |||
800 | if ($item->getHref() === false || $item->getHref() === null) { |
||
801 | $vars['class'][] = 'elgg-non-link'; |
||
802 | } |
||
803 | |||
804 | if (!isset($vars['rel']) && !isset($vars['is_trusted'])) { |
||
805 | $vars['is_trusted'] = true; |
||
806 | } |
||
807 | |||
808 | if ($item->getConfirmText()) { |
||
809 | $vars['confirm'] = $item->getConfirmText(); |
||
810 | } |
||
811 | |||
812 | return elgg_view('output/url', $vars); |
||
813 | } |
||
814 | |||
815 | /** |
||
816 | * Returns a string of a rendered entity. |
||
817 | * |
||
818 | * Entity views are either determined by setting the view property on the entity |
||
819 | * or by having a view named after the entity $type/$subtype. Entities that have |
||
820 | * neither a view property nor a defined $type/$subtype view will fall back to |
||
821 | * using the $type/default view. |
||
822 | * |
||
823 | * The entity view is called with the following in $vars: |
||
824 | * - \ElggEntity 'entity' The entity being viewed |
||
825 | * |
||
826 | * @tip This function can automatically appends annotations to entities if in full |
||
827 | * view and a handler is registered for the entity:annotate. See https://github.com/Elgg/Elgg/issues/964 and |
||
828 | * {@link elgg_view_entity_annotations()}. |
||
829 | * |
||
830 | * @param \ElggEntity $entity The entity to display |
||
831 | * @param array $vars Array of variables to pass to the entity view. |
||
832 | * 'full_view' Whether to show a full or condensed view. (Default: true) |
||
833 | * 'item_view' Alternative view used to render this entity |
||
834 | * |
||
835 | * @return string HTML to display or false |
||
836 | * @todo The annotation hook might be better as a generic plugin hook to append content. |
||
837 | */ |
||
838 | function elgg_view_entity(\ElggEntity $entity, array $vars = []) { |
||
839 | |||
840 | // No point continuing if entity is null |
||
841 | if (!$entity || !($entity instanceof \ElggEntity)) { |
||
842 | return false; |
||
843 | } |
||
844 | |||
845 | elgg_register_rss_link(); |
||
846 | |||
847 | $defaults = [ |
||
848 | 'full_view' => true, |
||
849 | ]; |
||
850 | |||
851 | $vars = array_merge($defaults, $vars); |
||
852 | |||
853 | $vars['entity'] = $entity; |
||
854 | |||
855 | $entity_type = $entity->getType(); |
||
856 | $entity_subtype = $entity->getSubtype(); |
||
857 | if (empty($entity_subtype)) { |
||
858 | $entity_subtype = 'default'; |
||
859 | } |
||
860 | |||
861 | $entity_views = [ |
||
862 | elgg_extract('item_view', $vars, ''), |
||
863 | "$entity_type/$entity_subtype", |
||
864 | "$entity_type/default", |
||
865 | ]; |
||
866 | |||
867 | $contents = ''; |
||
868 | foreach ($entity_views as $view) { |
||
869 | if (elgg_view_exists($view)) { |
||
870 | $contents = elgg_view($view, $vars); |
||
871 | break; |
||
872 | } |
||
873 | } |
||
874 | |||
875 | // Marcus Povey 20090616 : Speculative and low impact approach for fixing #964 |
||
876 | if ($vars['full_view']) { |
||
877 | $annotations = elgg_view_entity_annotations($entity, $vars['full_view']); |
||
878 | |||
879 | if ($annotations) { |
||
880 | $contents .= $annotations; |
||
881 | } |
||
882 | } |
||
883 | return $contents; |
||
884 | } |
||
885 | |||
886 | /** |
||
887 | * View the icon of an entity |
||
888 | * |
||
889 | * Entity views are determined by having a view named after the entity $type/$subtype. |
||
890 | * Entities that do not have a defined icon/$type/$subtype view will fall back to using |
||
891 | * the icon/$type/default view. |
||
892 | * |
||
893 | * @param \ElggEntity $entity The entity to display |
||
894 | * @param string $size The size: tiny, small, medium, large |
||
895 | * @param array $vars An array of variables to pass to the view. Some possible |
||
896 | * variables are img_class and link_class. See the |
||
897 | * specific icon view for more parameters. |
||
898 | * |
||
899 | * @return string HTML to display or false |
||
900 | */ |
||
901 | function elgg_view_entity_icon(\ElggEntity $entity, $size = 'medium', $vars = []) { |
||
902 | |||
903 | // No point continuing if entity is null |
||
904 | if (!$entity || !($entity instanceof \ElggEntity)) { |
||
905 | return false; |
||
906 | } |
||
907 | |||
908 | $vars['entity'] = $entity; |
||
909 | $vars['size'] = $size; |
||
910 | |||
911 | $entity_type = $entity->getType(); |
||
912 | |||
913 | $subtype = $entity->getSubtype(); |
||
914 | if (empty($subtype)) { |
||
915 | $subtype = 'default'; |
||
916 | } |
||
917 | |||
918 | $contents = ''; |
||
919 | if (elgg_view_exists("icon/$entity_type/$subtype")) { |
||
920 | $contents = elgg_view("icon/$entity_type/$subtype", $vars); |
||
921 | } |
||
922 | if (empty($contents)) { |
||
923 | $contents = elgg_view("icon/$entity_type/default", $vars); |
||
924 | } |
||
925 | if (empty($contents)) { |
||
926 | $contents = elgg_view("icon/default", $vars); |
||
927 | } |
||
928 | |||
929 | return $contents; |
||
930 | } |
||
931 | |||
932 | /** |
||
933 | * Returns a string of a rendered annotation. |
||
934 | * |
||
935 | * Annotation views are expected to be in annotation/$annotation_name. |
||
936 | * If a view is not found for $annotation_name, the default annotation/default |
||
937 | * will be used. |
||
938 | * |
||
939 | * @warning annotation/default is not currently defined in core. |
||
940 | * |
||
941 | * The annotation view is called with the following in $vars: |
||
942 | * - \ElggEntity 'annotation' The annotation being viewed. |
||
943 | * |
||
944 | * @param \ElggAnnotation $annotation The annotation to display |
||
945 | * @param array $vars Variable array for view. |
||
946 | * 'item_view' Alternative view used to render an annotation |
||
947 | * |
||
948 | * @return string/false Rendered annotation |
||
949 | */ |
||
950 | function elgg_view_annotation(\ElggAnnotation $annotation, array $vars = []) { |
||
951 | elgg_register_rss_link(); |
||
952 | |||
953 | $defaults = [ |
||
954 | 'full_view' => true, |
||
955 | ]; |
||
956 | |||
957 | $vars = array_merge($defaults, $vars); |
||
958 | $vars['annotation'] = $annotation; |
||
959 | |||
960 | $name = $annotation->name; |
||
961 | if (empty($name)) { |
||
962 | return false; |
||
963 | } |
||
964 | |||
965 | $annotation_views = [ |
||
966 | elgg_extract('item_view', $vars, ''), |
||
967 | "annotation/$name", |
||
968 | "annotation/default", |
||
969 | ]; |
||
970 | |||
971 | $contents = ''; |
||
972 | foreach ($annotation_views as $view) { |
||
973 | if (elgg_view_exists($view)) { |
||
974 | $contents = elgg_view($view, $vars); |
||
975 | break; |
||
976 | } |
||
977 | } |
||
978 | |||
979 | return $contents; |
||
980 | } |
||
981 | |||
982 | /** |
||
983 | * Returns a rendered list of entities with pagination. This function should be |
||
984 | * called by wrapper functions. |
||
985 | * |
||
986 | * @see elgg_list_entities() |
||
987 | * @see list_user_friends_objects() |
||
988 | * @see elgg_list_entities_from_metadata() |
||
989 | * @see elgg_list_entities_from_relationships() |
||
990 | * @see elgg_list_entities_from_annotations() |
||
991 | * |
||
992 | * @param array $entities Array of entities |
||
993 | * @param array $vars Display variables |
||
994 | * 'count' The total number of entities across all pages |
||
995 | * 'offset' The current indexing offset |
||
996 | * 'limit' The number of entities to display per page (default from settings) |
||
997 | * 'full_view' Display the full view of the entities? |
||
998 | * 'list_class' CSS class applied to the list |
||
999 | * 'item_class' CSS class applied to the list items |
||
1000 | * 'item_view' Alternative view to render list items |
||
1001 | * 'pagination' Display pagination? |
||
1002 | * 'base_url' Base URL of list (optional) |
||
1003 | * 'url_fragment' URL fragment to add to links if not present in base_url (optional) |
||
1004 | * 'position' Position of the pagination: before, after, or both |
||
1005 | * 'list_type' List type: 'list' (default), 'gallery' |
||
1006 | * 'list_type_toggle' Display the list type toggle? |
||
1007 | * 'no_results' Message to display if no results (string|Closure) |
||
1008 | * |
||
1009 | * @return string The rendered list of entities |
||
1010 | */ |
||
1011 | function elgg_view_entity_list($entities, array $vars = []) { |
||
1012 | $offset = (int) get_input('offset', 0); |
||
1013 | |||
1014 | // list type can be passed as request parameter |
||
1015 | $list_type = get_input('list_type', 'list'); |
||
1016 | |||
1017 | $defaults = [ |
||
1018 | 'items' => $entities, |
||
1019 | 'list_class' => 'elgg-list-entity', |
||
1020 | 'full_view' => true, |
||
1021 | 'pagination' => true, |
||
1022 | 'list_type' => $list_type, |
||
1023 | 'list_type_toggle' => false, |
||
1024 | 'offset' => $offset, |
||
1025 | 'limit' => null, |
||
1026 | ]; |
||
1027 | |||
1028 | $vars = array_merge($defaults, $vars); |
||
1029 | |||
1030 | View Code Duplication | if (!$vars["limit"] && !$vars["offset"]) { |
|
1031 | // no need for pagination if listing is unlimited |
||
1032 | $vars["pagination"] = false; |
||
1033 | } |
||
1034 | |||
1035 | if ($vars['list_type'] == 'table') { |
||
1036 | return elgg_view('page/components/table', $vars); |
||
1037 | } elseif ($vars['list_type'] == 'list') { |
||
1038 | return elgg_view('page/components/list', $vars); |
||
1039 | } else { |
||
1040 | return elgg_view('page/components/gallery', $vars); |
||
1041 | } |
||
1042 | } |
||
1043 | |||
1044 | /** |
||
1045 | * Returns a rendered list of annotations, plus pagination. This function |
||
1046 | * should be called by wrapper functions. |
||
1047 | * |
||
1048 | * @param array $annotations Array of annotations |
||
1049 | * @param array $vars Display variables |
||
1050 | * 'count' The total number of annotations across all pages |
||
1051 | * 'offset' The current indexing offset |
||
1052 | * 'limit' The number of annotations to display per page |
||
1053 | * 'full_view' Display the full view of the annotation? |
||
1054 | * 'list_class' CSS Class applied to the list |
||
1055 | * 'item_view' Alternative view to render list items |
||
1056 | * 'offset_key' The url parameter key used for offset |
||
1057 | * 'no_results' Message to display if no results (string|Closure) |
||
1058 | * |
||
1059 | * @return string The list of annotations |
||
1060 | * @access private |
||
1061 | */ |
||
1062 | function elgg_view_annotation_list($annotations, array $vars = []) { |
||
1063 | $defaults = [ |
||
1064 | 'items' => $annotations, |
||
1065 | 'offset' => null, |
||
1066 | 'limit' => null, |
||
1067 | 'list_class' => 'elgg-list-annotation elgg-annotation-list', // @todo remove elgg-annotation-list in Elgg 1.9 |
||
1068 | 'full_view' => true, |
||
1069 | 'offset_key' => 'annoff', |
||
1070 | ]; |
||
1071 | |||
1072 | $vars = array_merge($defaults, $vars); |
||
1073 | |||
1074 | View Code Duplication | if (!$vars["limit"] && !$vars["offset"]) { |
|
1075 | // no need for pagination if listing is unlimited |
||
1076 | $vars["pagination"] = false; |
||
1077 | } |
||
1078 | |||
1079 | return elgg_view('page/components/list', $vars); |
||
1080 | } |
||
1081 | |||
1082 | /** |
||
1083 | * Display a plugin-specified rendered list of annotations for an entity. |
||
1084 | * |
||
1085 | * This displays the output of functions registered to the entity:annotation, |
||
1086 | * $entity_type plugin hook. |
||
1087 | * |
||
1088 | * This is called automatically by the framework from {@link elgg_view_entity()} |
||
1089 | * |
||
1090 | * @param \ElggEntity $entity Entity |
||
1091 | * @param bool $full_view Display full view? |
||
1092 | * |
||
1093 | * @return mixed string or false on failure |
||
1094 | * @todo Change the hook name. |
||
1095 | */ |
||
1096 | function elgg_view_entity_annotations(\ElggEntity $entity, $full_view = true) { |
||
1097 | if (!($entity instanceof \ElggEntity)) { |
||
1098 | return false; |
||
1099 | } |
||
1100 | |||
1101 | $entity_type = $entity->getType(); |
||
1102 | |||
1103 | $annotations = elgg_trigger_plugin_hook('entity:annotate', $entity_type, |
||
1104 | [ |
||
1105 | 'entity' => $entity, |
||
1106 | 'full_view' => $full_view, |
||
1107 | ] |
||
1108 | ); |
||
1109 | |||
1110 | return $annotations; |
||
1111 | } |
||
1112 | |||
1113 | /** |
||
1114 | * Renders a title. |
||
1115 | * |
||
1116 | * This is a shortcut for {@elgg_view page/elements/title}. |
||
1117 | * |
||
1118 | * @param string $title The page title |
||
1119 | * @param array $vars View variables (was submenu be displayed? (deprecated)) |
||
1120 | * |
||
1121 | * @return string The HTML (etc) |
||
1122 | */ |
||
1123 | function elgg_view_title($title, array $vars = []) { |
||
1124 | $vars['title'] = $title; |
||
1125 | |||
1126 | return elgg_view('page/elements/title', $vars); |
||
1127 | } |
||
1128 | |||
1129 | /** |
||
1130 | * Displays a UNIX timestamp in a friendly way |
||
1131 | * |
||
1132 | * @see elgg_get_friendly_time() |
||
1133 | * |
||
1134 | * @param int $time A UNIX epoch timestamp |
||
1135 | * |
||
1136 | * @return string The friendly time HTML |
||
1137 | * @since 1.7.2 |
||
1138 | */ |
||
1139 | View Code Duplication | function elgg_view_friendly_time($time) { |
|
1140 | $view = 'output/friendlytime'; |
||
1141 | $vars = ['time' => $time]; |
||
1142 | $viewtype = elgg_view_exists($view) ? '' : 'default'; |
||
1143 | |||
1144 | return _elgg_view_under_viewtype($view, $vars, $viewtype); |
||
1145 | } |
||
1146 | |||
1147 | /** |
||
1148 | * Returns rendered comments and a comment form for an entity. |
||
1149 | * |
||
1150 | * @tip Plugins can override the output by registering a handler |
||
1151 | * for the comments, $entity_type hook. The handler is responsible |
||
1152 | * for formatting the comments and the add comment form. |
||
1153 | * |
||
1154 | * @param \ElggEntity $entity The entity to view comments of |
||
1155 | * @param bool $add_comment Include a form to add comments? |
||
1156 | * @param array $vars Variables to pass to comment view |
||
1157 | * |
||
1158 | * @return string|false Rendered comments or false on failure |
||
1159 | */ |
||
1160 | function elgg_view_comments($entity, $add_comment = true, array $vars = []) { |
||
1161 | if (!($entity instanceof \ElggEntity)) { |
||
1162 | return false; |
||
1163 | } |
||
1164 | |||
1165 | $vars['entity'] = $entity; |
||
1166 | $vars['show_add_form'] = $add_comment; |
||
1167 | $vars['class'] = elgg_extract('class', $vars, "{$entity->getSubtype()}-comments"); |
||
1168 | |||
1169 | $output = elgg_trigger_plugin_hook('comments', $entity->getType(), $vars, false); |
||
1170 | if ($output !== false) { |
||
1171 | return $output; |
||
1172 | } else { |
||
1173 | return elgg_view('page/elements/comments', $vars); |
||
1174 | } |
||
1175 | } |
||
1176 | |||
1177 | /** |
||
1178 | * Wrapper function for the image block display pattern. |
||
1179 | * |
||
1180 | * Fixed width media on the side (image, icon, flash, etc.). |
||
1181 | * Descriptive content filling the rest of the column. |
||
1182 | * |
||
1183 | * @note Use the $vars "image_alt" key to set an image on the right. If you do, you may pass |
||
1184 | * in an empty string for $image to have only the right image. |
||
1185 | * |
||
1186 | * This is a shortcut for {@elgg_view page/components/image_block}. |
||
1187 | * |
||
1188 | * @param string $image The icon and other information |
||
1189 | * @param string $body Description content |
||
1190 | * @param array $vars Additional parameters for the view |
||
1191 | * |
||
1192 | * @return string |
||
1193 | * @since 1.8.0 |
||
1194 | */ |
||
1195 | function elgg_view_image_block($image, $body, $vars = []) { |
||
1196 | $vars['image'] = $image; |
||
1197 | $vars['body'] = $body; |
||
1198 | return elgg_view('page/components/image_block', $vars); |
||
1199 | } |
||
1200 | |||
1201 | /** |
||
1202 | * Wrapper function for the module display pattern. |
||
1203 | * |
||
1204 | * Box with header, body, footer |
||
1205 | * |
||
1206 | * This is a shortcut for {@elgg_view page/components/module}. |
||
1207 | * |
||
1208 | * @param string $type The type of module (main, info, popup, aside, etc.) |
||
1209 | * @param string $title A title to put in the header |
||
1210 | * @param string $body Content of the module |
||
1211 | * @param array $vars Additional parameters for the module |
||
1212 | * |
||
1213 | * @return string |
||
1214 | * @since 1.8.0 |
||
1215 | */ |
||
1216 | function elgg_view_module($type, $title, $body, array $vars = []) { |
||
1217 | $vars['type'] = $type; |
||
1218 | $vars['title'] = $title; |
||
1219 | $vars['body'] = $body; |
||
1220 | return elgg_view('page/components/module', $vars); |
||
1221 | } |
||
1222 | |||
1223 | /** |
||
1224 | * Renders a human-readable representation of a river item |
||
1225 | * |
||
1226 | * @param \ElggRiverItem $item A river item object |
||
1227 | * @param array $vars An array of variables for the view |
||
1228 | * 'item_view' Alternative view to render the item |
||
1229 | * @return string returns empty string if could not be rendered |
||
1230 | */ |
||
1231 | function elgg_view_river_item($item, array $vars = []) { |
||
1232 | if (!($item instanceof \ElggRiverItem)) { |
||
1233 | return ''; |
||
1234 | } |
||
1235 | // checking default viewtype since some viewtypes do not have unique views per item (rss) |
||
1236 | $view = $item->getView(); |
||
1237 | if (!$view || !elgg_view_exists($view, 'default')) { |
||
1238 | return ''; |
||
1239 | } |
||
1240 | |||
1241 | $subject = $item->getSubjectEntity(); |
||
1242 | $object = $item->getObjectEntity(); |
||
1243 | if (!$subject || !$object) { |
||
1244 | // subject is disabled or subject/object deleted |
||
1245 | return ''; |
||
1246 | } |
||
1247 | |||
1248 | // @todo this needs to be cleaned up |
||
1249 | // Don't hide objects in closed groups that a user can see. |
||
1250 | // see https://github.com/elgg/elgg/issues/4789 |
||
1251 | // else { |
||
1252 | // // hide based on object's container |
||
1253 | // $visibility = \Elgg\GroupItemVisibility::factory($object->container_guid); |
||
1254 | // if ($visibility->shouldHideItems) { |
||
1255 | // return ''; |
||
1256 | // } |
||
1257 | // } |
||
1258 | |||
1259 | $vars['item'] = $item; |
||
1260 | |||
1261 | $river_views = [ |
||
1262 | elgg_extract('item_view', $vars, ''), |
||
1263 | "river/item", // important for other viewtypes, e.g. "rss" |
||
1264 | $view, |
||
1265 | ]; |
||
1266 | |||
1267 | $contents = ''; |
||
1268 | foreach ($river_views as $view) { |
||
1269 | if (elgg_view_exists($view)) { |
||
1270 | $contents = elgg_view($view, $vars); |
||
1271 | break; |
||
1272 | } |
||
1273 | } |
||
1274 | |||
1275 | return $contents; |
||
1276 | } |
||
1277 | |||
1278 | /** |
||
1279 | * Convenience function for generating a form from a view in a standard location. |
||
1280 | * |
||
1281 | * This function assumes that the body of the form is located at "forms/$action" and |
||
1282 | * sets the action by default to "action/$action". Automatically wraps the forms/$action |
||
1283 | * view with a <form> tag and inserts the anti-csrf security tokens. |
||
1284 | * |
||
1285 | * @tip This automatically appends elgg-form-action-name to the form's class. It replaces any |
||
1286 | * slashes with dashes (blog/save becomes elgg-form-blog-save) |
||
1287 | * |
||
1288 | * @example |
||
1289 | * <code>echo elgg_view_form('login');</code> |
||
1290 | * |
||
1291 | * This would assume a "login" form body to be at "forms/login" and would set the action |
||
1292 | * of the form to "http://yoursite.com/action/login". |
||
1293 | * |
||
1294 | * If elgg_view('forms/login') is: |
||
1295 | * <input type="text" name="username" /> |
||
1296 | * <input type="password" name="password" /> |
||
1297 | * |
||
1298 | * Then elgg_view_form('login') generates: |
||
1299 | * <form action="http://yoursite.com/action/login" method="post"> |
||
1300 | * ...security tokens... |
||
1301 | * <input type="text" name="username" /> |
||
1302 | * <input type="password" name="password" /> |
||
1303 | * </form> |
||
1304 | * |
||
1305 | * @param string $action The name of the action. An action name does not include |
||
1306 | * the leading "action/". For example, "login" is an action name. |
||
1307 | * @param array $form_vars $vars environment passed to the "input/form" view |
||
1308 | * @param array $body_vars $vars environment passed to the "forms/$action" view |
||
1309 | * |
||
1310 | * @return string The complete form |
||
1311 | */ |
||
1312 | function elgg_view_form($action, $form_vars = [], $body_vars = []) { |
||
1313 | 3 | return _elgg_services()->forms->render($action, $form_vars, $body_vars); |
|
1314 | } |
||
1315 | |||
1316 | /** |
||
1317 | * Sets form footer and defers its rendering until the form view and extensions have been rendered. |
||
1318 | * Deferring footer rendering allows plugins to extend the form view while maintaining |
||
1319 | * logical DOM structure. |
||
1320 | * Footer will be rendered using 'elements/forms/footer' view after form body has finished rendering |
||
1321 | * |
||
1322 | * @param string $footer Footer |
||
1323 | * @return bool |
||
1324 | */ |
||
1325 | function elgg_set_form_footer($footer = '') { |
||
1326 | 1 | return _elgg_services()->forms->setFooter($footer); |
|
1327 | } |
||
1328 | |||
1329 | /** |
||
1330 | * Returns currently set footer, or false if not in the form rendering stack |
||
1331 | * @return string|false |
||
1332 | */ |
||
1333 | function elgg_get_form_footer() { |
||
1334 | return _elgg_services()->forms->getFooter(); |
||
1335 | } |
||
1336 | |||
1337 | /** |
||
1338 | * Renders a form field |
||
1339 | * |
||
1340 | * @param string $input_type Input type, used to generate an input view ("input/$input_type") |
||
1341 | * @param array $vars Fields and input vars. |
||
1342 | * Field vars contain both field and input params. 'label', 'help', |
||
1343 | * and 'field_class' params will not be passed on to the input view. |
||
1344 | * Others, including 'required' and 'id', will be available to the |
||
1345 | * input view. Both 'label' and 'help' params accept HTML, and |
||
1346 | * will be printed unescaped within their wrapper element. |
||
1347 | * @return string |
||
1348 | * |
||
1349 | * @since 2.1 |
||
1350 | * @deprecated 2.3 Use elgg_view_field() |
||
1351 | */ |
||
1352 | function elgg_view_input($input_type, array $vars = []) { |
||
1353 | |||
1354 | elgg_deprecated_notice(__FUNCTION__ . '() is deprecated. Use elgg_view_field()', '2.3'); |
||
1355 | |||
1356 | $vars['#type'] = $input_type; |
||
1357 | |||
1358 | if (isset($vars['label']) && $input_type !== 'checkbox') { |
||
1359 | $vars['#label'] = $vars['label']; |
||
1360 | unset($vars['label']); |
||
1361 | } |
||
1362 | View Code Duplication | if (isset($vars['help'])) { |
|
1363 | $vars['#help'] = $vars['help']; |
||
1364 | unset($vars['help']); |
||
1365 | } |
||
1366 | if (isset($vars['field_class'])) { |
||
1367 | $vars['#class'] = $vars['field_class']; |
||
1368 | unset($vars['field_class']); |
||
1369 | } |
||
1370 | |||
1371 | return elgg_view_field($vars); |
||
1372 | } |
||
1373 | |||
1374 | /** |
||
1375 | * Renders a form field, usually with a wrapper element, a label, help text, etc. |
||
1376 | * |
||
1377 | * @param array $params Field parameters and variables for the input view. |
||
1378 | * Keys not prefixed with hash (#) are passed to the input view as $vars. |
||
1379 | * Keys prefixed with a hash specify the field wrapper (.elgg-view-field) output. |
||
1380 | * - #type: specifies input view. E.g. "text" uses the view "input/text". |
||
1381 | * - #label: field label HTML |
||
1382 | * - #help: field help HTML |
||
1383 | * - #class: field class name |
||
1384 | * Note: Both #label and #help are printed unescaped within their wrapper element. |
||
1385 | * Note: Some fields (like input/checkbox) need special attention because #label and label serve different purposes |
||
1386 | * "#label" will be used as a label in the field wrapper but "label" will be used in the input view |
||
1387 | * |
||
1388 | * @return string |
||
1389 | * @since 2.3 |
||
1390 | */ |
||
1391 | function elgg_view_field(array $params = []) { |
||
1392 | |||
1393 | if (empty($params['#type'])) { |
||
1394 | _elgg_services()->logger->error(__FUNCTION__ . '(): $params["#type"] is required.'); |
||
1395 | return ''; |
||
1396 | } |
||
1397 | |||
1398 | $input_type = $params['#type']; |
||
1399 | if (!elgg_view_exists("input/$input_type")) { |
||
1400 | return ''; |
||
1401 | } |
||
1402 | |||
1403 | $hidden_types = ['hidden', 'securitytoken']; |
||
1404 | if (in_array($input_type, $hidden_types)) { |
||
1405 | unset($params['#type']); |
||
1406 | unset($params['#label']); |
||
1407 | unset($params['#help']); |
||
1408 | unset($params['#class']); |
||
1409 | return elgg_view("input/$input_type", $params); |
||
1410 | } |
||
1411 | |||
1412 | $id = elgg_extract('id', $params); |
||
1413 | if (!$id) { |
||
1414 | $id = "elgg-field-" . base_convert(mt_rand(), 10, 36); |
||
1415 | $params['id'] = $id; |
||
1416 | } |
||
1417 | |||
1418 | // $vars passed to label, help and field wrapper views |
||
1419 | $element_vars = []; |
||
1420 | |||
1421 | // $vars passed to input/$input_name |
||
1422 | $input_vars = []; |
||
1423 | |||
1424 | $make_special_checkbox_label = false; |
||
1425 | if ($input_type == 'checkbox' && (isset($params['label']) || isset($params['#label']))) { |
||
1426 | if (isset($params['#label']) && isset($params['label'])) { |
||
1427 | $params['label_tag'] = 'div'; |
||
1428 | } else { |
||
1429 | $label = elgg_extract('label', $params); |
||
1430 | $label = elgg_extract('#label', $params, $label); |
||
1431 | |||
1432 | $params['#label'] = $label; |
||
1433 | unset($params['label']); |
||
1434 | |||
1435 | // Single checkbox input view gets special treatment |
||
1436 | // We don't want the field label to appear a checkbox without a label |
||
1437 | $make_special_checkbox_label = true; |
||
1438 | } |
||
1439 | } |
||
1440 | |||
1441 | // first pass non-hash keys into both |
||
1442 | foreach ($params as $key => $value) { |
||
1443 | if ($key[0] !== '#') { |
||
1444 | $element_vars[$key] = $value; |
||
1445 | $input_vars[$key] = $value; |
||
1446 | } |
||
1447 | } |
||
1448 | |||
1449 | // field input view needs this |
||
1450 | $input_vars['input_type'] = $input_type; |
||
1451 | |||
1452 | // field views get more data |
||
1453 | $element_vars['input_type'] = $input_type; |
||
1454 | |||
1455 | unset($element_vars['class']); |
||
1456 | if (isset($params['#class'])) { |
||
1457 | $element_vars['class'] = $params['#class']; |
||
1458 | } |
||
1459 | unset($element_vars['help']); |
||
1460 | if (isset($params['#help'])) { |
||
1461 | $element_vars['help'] = $params['#help']; |
||
1462 | } |
||
1463 | unset($element_vars['label']); |
||
1464 | if (isset($params['#label'])) { |
||
1465 | $element_vars['label'] = $params['#label']; |
||
1466 | } |
||
1467 | |||
1468 | // wrap if present |
||
1469 | $element_vars['label'] = elgg_view('elements/forms/label', $element_vars); |
||
1470 | $element_vars['help'] = elgg_view('elements/forms/help', $element_vars); |
||
1471 | |||
1472 | if ($make_special_checkbox_label) { |
||
1473 | $input_vars['label'] = $element_vars['label']; |
||
1474 | $input_vars['label_tag'] = 'div'; |
||
1475 | unset($element_vars['label']); |
||
1476 | } |
||
1477 | $element_vars['input'] = elgg_view("elements/forms/input", $input_vars); |
||
1478 | |||
1479 | return elgg_view('elements/forms/field', $element_vars); |
||
1480 | } |
||
1481 | |||
1482 | /** |
||
1483 | * Create a tagcloud for viewing |
||
1484 | * |
||
1485 | * @see elgg_get_tags |
||
1486 | * |
||
1487 | * @param array $options Any elgg_get_tags() options except: |
||
1488 | * |
||
1489 | * type => must be single entity type |
||
1490 | * |
||
1491 | * subtype => must be single entity subtype |
||
1492 | * |
||
1493 | * @return string |
||
1494 | * @since 1.7.1 |
||
1495 | */ |
||
1496 | function elgg_view_tagcloud(array $options = []) { |
||
1497 | |||
1498 | $type = $subtype = ''; |
||
1499 | if (isset($options['type'])) { |
||
1500 | $type = $options['type']; |
||
1501 | } |
||
1502 | if (isset($options['subtype'])) { |
||
1503 | $subtype = $options['subtype']; |
||
1504 | } |
||
1505 | |||
1506 | $tag_data = elgg_get_tags($options); |
||
1507 | return elgg_view("output/tagcloud", [ |
||
1508 | 'value' => $tag_data, |
||
1509 | 'type' => $type, |
||
1510 | 'subtype' => $subtype, |
||
1511 | ]); |
||
1512 | } |
||
1513 | |||
1514 | /** |
||
1515 | * View an item in a list |
||
1516 | * |
||
1517 | * @param mixed $item Entity, annotation, river item, or other data |
||
1518 | * @param array $vars Additional parameters for the rendering |
||
1519 | * 'item_view' - Alternative view used to render list items |
||
1520 | * This parameter is required if rendering |
||
1521 | * list items that are not entity, annotation or river |
||
1522 | * @return string |
||
1523 | * @since 1.8.0 |
||
1524 | * @access private |
||
1525 | */ |
||
1526 | function elgg_view_list_item($item, array $vars = []) { |
||
1527 | |||
1528 | if ($item instanceof \ElggEntity) { |
||
1529 | return elgg_view_entity($item, $vars); |
||
1530 | } else if ($item instanceof \ElggAnnotation) { |
||
1531 | return elgg_view_annotation($item, $vars); |
||
1532 | } else if ($item instanceof \ElggRiverItem) { |
||
1533 | return elgg_view_river_item($item, $vars); |
||
1534 | } |
||
1535 | |||
1536 | $view = elgg_extract('item_view', $vars); |
||
1537 | if ($view && elgg_view_exists($view)) { |
||
1538 | $vars['item'] = $item; |
||
1539 | return elgg_view($view, $vars); |
||
1540 | } |
||
1541 | |||
1542 | return ''; |
||
1543 | } |
||
1544 | |||
1545 | /** |
||
1546 | * View one of the icons |
||
1547 | * |
||
1548 | * Shorthand for <span class="elgg-icon elgg-icon-$name"></span> |
||
1549 | * |
||
1550 | * @param string $name The specific icon to display |
||
1551 | * @param mixed $vars The additional classname as a string ('float', 'float-alt' or a custom class) |
||
1552 | * or an array of variables (array('class' => 'float')) to pass to the icon view. |
||
1553 | * |
||
1554 | * @return string The html for displaying an icon |
||
1555 | * @throws InvalidArgumentException |
||
1556 | */ |
||
1557 | function elgg_view_icon($name, $vars = []) { |
||
1558 | if (empty($vars)) { |
||
1559 | $vars = []; |
||
1560 | } |
||
1561 | |||
1562 | if (is_string($vars)) { |
||
1563 | $vars = ['class' => $vars]; |
||
1564 | } |
||
1565 | |||
1566 | if (!is_array($vars)) { |
||
1567 | throw new \InvalidArgumentException('$vars needs to be a string or an array'); |
||
1568 | } |
||
1569 | |||
1570 | if (!array_key_exists('class', $vars)) { |
||
1571 | $vars['class'] = []; |
||
1572 | } |
||
1573 | |||
1574 | if (!is_array($vars['class'])) { |
||
1575 | $vars['class'] = [$vars['class']]; |
||
1576 | } |
||
1577 | |||
1578 | $vars['class'][] = "elgg-icon-$name"; |
||
1579 | |||
1580 | return elgg_view("output/icon", $vars); |
||
1581 | } |
||
1582 | |||
1583 | /** |
||
1584 | * Include the RSS icon link and link element in the head |
||
1585 | * |
||
1586 | * @return void |
||
1587 | */ |
||
1588 | function elgg_register_rss_link() { |
||
1589 | _elgg_config()->_elgg_autofeed = true; |
||
1590 | } |
||
1591 | |||
1592 | /** |
||
1593 | * Remove the RSS icon link and link element from the head |
||
1594 | * |
||
1595 | * @return void |
||
1596 | */ |
||
1597 | function elgg_unregister_rss_link() { |
||
1598 | _elgg_config()->_elgg_autofeed = false; |
||
1599 | } |
||
1600 | |||
1601 | /** |
||
1602 | * Should the RSS view of this URL be linked to? |
||
1603 | * |
||
1604 | * @return bool |
||
1605 | * @access private |
||
1606 | */ |
||
1607 | function _elgg_has_rss_link() { |
||
1608 | 4 | if (isset($GLOBALS['autofeed']) && is_bool($GLOBALS['autofeed'])) { |
|
1609 | elgg_deprecated_notice('Do not set the global $autofeed. Use elgg_register_rss_link()', '2.1'); |
||
1610 | return $GLOBALS['autofeed']; |
||
1611 | } |
||
1612 | 4 | return (bool) _elgg_services()->config->getVolatile('_elgg_autofeed'); |
|
1613 | } |
||
1614 | |||
1615 | /** |
||
1616 | * Auto-registers views from a location. |
||
1617 | * |
||
1618 | * @note Views in plugin/views/ are automatically registered for active plugins. |
||
1619 | * Plugin authors would only need to call this if optionally including |
||
1620 | * an entire views structure. |
||
1621 | * |
||
1622 | * @param string $view_base Optional The base of the view name without the view type. |
||
1623 | * @param string $folder Required The folder to begin looking in |
||
1624 | * @param string $ignored This argument is ignored |
||
1625 | * @param string $viewtype The type of view we're looking at (default, rss, etc) |
||
1626 | * |
||
1627 | * @return bool returns false if folder can't be read |
||
1628 | * @since 1.7.0 |
||
1629 | * @see elgg_set_view_location() |
||
1630 | * @access private |
||
1631 | */ |
||
1632 | function autoregister_views($view_base, $folder, $ignored, $viewtype) { |
||
1633 | return _elgg_services()->views->autoregisterViews($view_base, $folder, $viewtype); |
||
1634 | } |
||
1635 | |||
1636 | /** |
||
1637 | * Minifies simplecache CSS and JS views by handling the "simplecache:generate" hook |
||
1638 | * |
||
1639 | * @param string $hook The name of the hook |
||
1640 | * @param string $type View type (css, js, or unknown) |
||
1641 | * @param string $content Content of the view |
||
1642 | * @param array $params Array of parameters |
||
1643 | * |
||
1644 | * @return string|null View content minified (if css/js type) |
||
1645 | * @access private |
||
1646 | */ |
||
1647 | function _elgg_views_minify($hook, $type, $content, $params) { |
||
1648 | if (preg_match('~[\.-]min\.~', $params['view'])) { |
||
1649 | // bypass minification |
||
1650 | return; |
||
1651 | } |
||
1652 | |||
1653 | if ($type == 'js') { |
||
1654 | if (_elgg_config()->simplecache_minify_js) { |
||
1655 | return JSMin::minify($content); |
||
1656 | } |
||
1657 | } elseif ($type == 'css') { |
||
1658 | if (_elgg_config()->simplecache_minify_css) { |
||
1659 | $cssmin = new CSSmin(); |
||
1660 | return $cssmin->run($content); |
||
1661 | } |
||
1662 | } |
||
1663 | } |
||
1664 | |||
1665 | /** |
||
1666 | * Preprocesses CSS views sent by /cache URLs |
||
1667 | * |
||
1668 | * @param string $hook The name of the hook "simplecache:generate" or "cache:generate" |
||
1669 | * @param string $type "css" |
||
1670 | * @param string $content Content of the view |
||
1671 | * @param array $params Array of parameters |
||
1672 | * |
||
1673 | * @return string|null View content |
||
1674 | * @access private |
||
1675 | */ |
||
1676 | function _elgg_views_preprocess_css($hook, $type, $content, $params) { |
||
1677 | $options = [ |
||
1678 | 'minify' => false, // minify handled by _elgg_views_minify |
||
1679 | 'formatter' => 'single-line', // shows lowest byte size |
||
1680 | 'versioning' => false, // versioning done by Elgg |
||
1681 | 'rewrite_import_urls' => false, |
||
1682 | ]; |
||
1683 | |||
1684 | return csscrush_string($content, $options); |
||
1685 | } |
||
1686 | |||
1687 | /** |
||
1688 | * Inserts module names into anonymous modules by handling the "simplecache:generate" hook. |
||
1689 | * |
||
1690 | * @param string $hook The name of the hook |
||
1691 | * @param string $type View type (css, js, or unknown) |
||
1692 | * @param string $content Content of the view |
||
1693 | * @param array $params Array of parameters |
||
1694 | * |
||
1695 | * @return string|null View content minified (if css/js type) |
||
1696 | * @access private |
||
1697 | */ |
||
1698 | function _elgg_views_amd($hook, $type, $content, $params) { |
||
1699 | $filter = new \Elgg\Amd\ViewFilter(); |
||
1700 | return $filter->filter($params['view'], $content); |
||
1701 | } |
||
1702 | |||
1703 | /** |
||
1704 | * Sends X-Frame-Options header on page requests |
||
1705 | * |
||
1706 | * @access private |
||
1707 | */ |
||
1708 | function _elgg_views_send_header_x_frame_options() { |
||
1709 | header('X-Frame-Options: SAMEORIGIN'); |
||
1710 | } |
||
1711 | |||
1712 | /** |
||
1713 | * Is there a chance a plugin is altering this view? |
||
1714 | * |
||
1715 | * @note Must be called after the [init, system] event, ideally as late as possible. |
||
1716 | * |
||
1717 | * @note Always returns true if the view's location is set in /engine/views.php. Elgg does not keep |
||
1718 | * track of the defaults for those locations. |
||
1719 | * |
||
1720 | * <code> |
||
1721 | * // check a view in core |
||
1722 | * if (_elgg_view_may_be_altered('foo/bar', 'foo/bar.php')) { |
||
1723 | * // use the view for BC |
||
1724 | * } |
||
1725 | * |
||
1726 | * // check a view in a bundled plugin |
||
1727 | * $dir = __DIR__ . "/views/" . elgg_get_viewtype(); |
||
1728 | * if (_elgg_view_may_be_altered('foo.css', "$dir/foo.css.php")) { |
||
1729 | * // use the view for BC |
||
1730 | * } |
||
1731 | * </code> |
||
1732 | * |
||
1733 | * @param string $view View name. E.g. "elgg/init.js" |
||
1734 | * @param string $path Absolute file path, or path relative to the viewtype directory. E.g. "elgg/init.js.php" |
||
1735 | * |
||
1736 | * @return bool |
||
1737 | * @access private |
||
1738 | */ |
||
1739 | function _elgg_view_may_be_altered($view, $path) { |
||
1740 | $views = _elgg_services()->views; |
||
1741 | |||
1742 | if ($views->viewIsExtended($view) || $views->viewHasHookHandlers($view)) { |
||
1743 | return true; |
||
1744 | } |
||
1745 | |||
1746 | $viewtype = elgg_get_viewtype(); |
||
1747 | |||
1748 | // check location |
||
1749 | if (0 === strpos($path, '/') || preg_match('~^([A-Za-z]\:)?\\\\~', $path)) { |
||
1750 | // absolute path |
||
1751 | $expected_path = $path; |
||
1752 | } else { |
||
1753 | // relative path |
||
1754 | $root = dirname(dirname(__DIR__)); |
||
1755 | $expected_path = "$root/views/$viewtype/" . ltrim($path, '/\\'); |
||
1756 | } |
||
1757 | |||
1758 | $view_path = $views->findViewFile($view, $viewtype); |
||
1759 | |||
1760 | return realpath($view_path) !== realpath($expected_path); |
||
1761 | } |
||
1762 | |||
1763 | /** |
||
1764 | * Initialize viewtypes on system boot event |
||
1765 | * This ensures simplecache is cleared during upgrades. See #2252 |
||
1766 | * |
||
1767 | * @return void |
||
1768 | * @access private |
||
1769 | * @elgg_event_handler boot system |
||
1770 | */ |
||
1771 | function elgg_views_boot() { |
||
1772 | if (!elgg_get_config('system_cache_loaded')) { |
||
1773 | // Core view files in /views |
||
1774 | _elgg_services()->views->registerPluginViews(realpath(__DIR__ . '/../../')); |
||
1775 | |||
1776 | // Core view definitions in /engine/views.php |
||
1777 | $file = dirname(__DIR__) . '/views.php'; |
||
1778 | View Code Duplication | if (is_file($file)) { |
|
1 ignored issue
–
show
|
|||
1779 | $spec = Includer::includeFile($file); |
||
1780 | if (is_array($spec)) { |
||
1781 | _elgg_services()->views->mergeViewsSpec($spec); |
||
1782 | } |
||
1783 | } |
||
1784 | } |
||
1785 | |||
1786 | // on every page |
||
1787 | |||
1788 | // jQuery and UI must come before require. See #9024 |
||
1789 | elgg_register_js('jquery', elgg_get_simplecache_url('jquery.js'), 'head'); |
||
1790 | elgg_load_js('jquery'); |
||
1791 | |||
1792 | elgg_register_js('jquery-ui', elgg_get_simplecache_url('jquery-ui.js'), 'head'); |
||
1793 | elgg_load_js('jquery-ui'); |
||
1794 | |||
1795 | elgg_register_js('elgg.require_config', elgg_get_simplecache_url('elgg/require_config.js'), 'head'); |
||
1796 | elgg_load_js('elgg.require_config'); |
||
1797 | |||
1798 | elgg_register_js('require', elgg_get_simplecache_url('require.js'), 'head'); |
||
1799 | elgg_load_js('require'); |
||
1800 | |||
1801 | elgg_register_js('elgg', elgg_get_simplecache_url('elgg.js'), 'head'); |
||
1802 | elgg_load_js('elgg'); |
||
1803 | |||
1804 | elgg_register_css('font-awesome', elgg_get_simplecache_url('font-awesome/css/font-awesome.css')); |
||
1805 | elgg_load_css('font-awesome'); |
||
1806 | |||
1807 | elgg_register_css('elgg', elgg_get_simplecache_url('elgg.css')); |
||
1808 | elgg_load_css('elgg'); |
||
1809 | |||
1810 | elgg_register_simplecache_view('elgg/init.js'); |
||
1811 | |||
1812 | elgg_extend_view('elgg.css', 'lightbox/elgg-colorbox-theme/colorbox.css'); |
||
1813 | |||
1814 | elgg_define_js('jquery.ui.autocomplete.html', [ |
||
1815 | 'deps' => ['jquery-ui'], |
||
1816 | ]); |
||
1817 | |||
1818 | elgg_register_js('elgg.avatar_cropper', elgg_get_simplecache_url('elgg/ui.avatar_cropper.js')); |
||
1819 | |||
1820 | // @deprecated 2.2 |
||
1821 | elgg_register_js('elgg.ui.river', elgg_get_simplecache_url('elgg/ui.river.js')); |
||
1822 | |||
1823 | elgg_register_js('jquery.imgareaselect', elgg_get_simplecache_url('jquery.imgareaselect.js')); |
||
1824 | elgg_register_css('jquery.imgareaselect', elgg_get_simplecache_url('jquery.imgareaselect.css')); |
||
1825 | |||
1826 | elgg_register_css('jquery.treeview', elgg_get_simplecache_url('jquery-treeview/jquery.treeview.css')); |
||
1827 | elgg_define_js('jquery.treeview', [ |
||
1828 | 'src' => elgg_get_simplecache_url('jquery-treeview/jquery.treeview.js'), |
||
1829 | 'exports' => 'jQuery.fn.treeview', |
||
1830 | 'deps' => ['jquery'], |
||
1831 | ]); |
||
1832 | |||
1833 | elgg_register_ajax_view('languages.js'); |
||
1834 | |||
1835 | // pre-process CSS regardless of simplecache |
||
1836 | elgg_register_plugin_hook_handler('cache:generate', 'css', '_elgg_views_preprocess_css'); |
||
1837 | elgg_register_plugin_hook_handler('simplecache:generate', 'css', '_elgg_views_preprocess_css'); |
||
1838 | |||
1839 | elgg_register_plugin_hook_handler('simplecache:generate', 'js', '_elgg_views_amd'); |
||
1840 | elgg_register_plugin_hook_handler('simplecache:generate', 'css', '_elgg_views_minify'); |
||
1841 | elgg_register_plugin_hook_handler('simplecache:generate', 'js', '_elgg_views_minify'); |
||
1842 | |||
1843 | elgg_register_plugin_hook_handler('output:before', 'page', '_elgg_views_send_header_x_frame_options'); |
||
1844 | |||
1845 | // registered with high priority for BC |
||
1846 | // prior to 2.2 registration used to take place in _elgg_views_prepare_head() before the hook was triggered |
||
1847 | elgg_register_plugin_hook_handler('head', 'page', '_elgg_views_prepare_favicon_links', 1); |
||
1848 | |||
1849 | // set default icon sizes - can be overridden in settings.php or with plugin |
||
1850 | if (!_elgg_services()->config->getVolatile('icon_sizes')) { |
||
1851 | $icon_sizes = [ |
||
1852 | 'topbar' => ['w' => 16, 'h' => 16, 'square' => true, 'upscale' => true], |
||
1853 | 'tiny' => ['w' => 25, 'h' => 25, 'square' => true, 'upscale' => true], |
||
1854 | 'small' => ['w' => 40, 'h' => 40, 'square' => true, 'upscale' => true], |
||
1855 | 'medium' => ['w' => 100, 'h' => 100, 'square' => true, 'upscale' => true], |
||
1856 | 'large' => ['w' => 200, 'h' => 200, 'square' => false, 'upscale' => false], |
||
1857 | 'master' => ['w' => 550, 'h' => 550, 'square' => false, 'upscale' => false], |
||
1858 | ]; |
||
1859 | elgg_set_config('icon_sizes', $icon_sizes); |
||
1860 | } |
||
1861 | |||
1862 | // Configure lightbox |
||
1863 | elgg_register_plugin_hook_handler('elgg.data', 'site', '_elgg_set_lightbox_config'); |
||
1864 | } |
||
1865 | |||
1866 | /** |
||
1867 | * Get the site data to be merged into "elgg" in elgg.js. |
||
1868 | * |
||
1869 | * Unlike _elgg_get_js_page_data(), the keys returned are literal expressions. |
||
1870 | * |
||
1871 | * @return array |
||
1872 | * @access private |
||
1873 | */ |
||
1874 | function _elgg_get_js_site_data() { |
||
1875 | $language = _elgg_config()->language; |
||
1876 | if (!$language) { |
||
1877 | $language = 'en'; |
||
1878 | } |
||
1879 | |||
1880 | return [ |
||
1881 | 'elgg.data' => (object) elgg_trigger_plugin_hook('elgg.data', 'site', null, []), |
||
1882 | 'elgg.version' => elgg_get_version(), |
||
1883 | 'elgg.release' => elgg_get_version(true), |
||
1884 | 'elgg.config.wwwroot' => elgg_get_site_url(), |
||
1885 | |||
1886 | // refresh token 3 times during its lifetime (in microseconds 1000 * 1/3) |
||
1887 | 'elgg.security.interval' => (int) _elgg_services()->actions->getActionTokenTimeout() * 333, |
||
1888 | 'elgg.config.language' => $language, |
||
1889 | ]; |
||
1890 | } |
||
1891 | |||
1892 | /** |
||
1893 | * Get the initial contents of "elgg" client side. Will be extended by elgg.js. |
||
1894 | * |
||
1895 | * @return array |
||
1896 | * @access private |
||
1897 | */ |
||
1898 | function _elgg_get_js_page_data() { |
||
1899 | $data = elgg_trigger_plugin_hook('elgg.data', 'page', null, []); |
||
1900 | if (!is_array($data)) { |
||
1901 | elgg_log('"elgg.data" plugin hook handlers must return an array. Returned ' . gettype($data) . '.', 'ERROR'); |
||
1902 | $data = []; |
||
1903 | } |
||
1904 | |||
1905 | $elgg = [ |
||
1906 | 'config' => [ |
||
1907 | 'lastcache' => (int) _elgg_config()->lastcache, |
||
1908 | 'viewtype' => elgg_get_viewtype(), |
||
1909 | 'simplecache_enabled' => (int) elgg_is_simplecache_enabled(), |
||
1910 | 'current_language' => get_current_language(), |
||
1911 | ], |
||
1912 | 'security' => [ |
||
1913 | 'token' => [ |
||
1914 | '__elgg_ts' => $ts = time(), |
||
1915 | '__elgg_token' => generate_action_token($ts), |
||
1916 | ], |
||
1917 | ], |
||
1918 | 'session' => [ |
||
1919 | 'user' => null, |
||
1920 | 'token' => _elgg_services()->session->get('__elgg_session'), |
||
1921 | ], |
||
1922 | '_data' => (object) $data, |
||
1923 | ]; |
||
1924 | |||
1925 | if (_elgg_config()->elgg_load_sync_code) { |
||
1926 | $elgg['config']['load_sync_code'] = true; |
||
1927 | } |
||
1928 | |||
1929 | $page_owner = elgg_get_page_owner_entity(); |
||
1930 | if ($page_owner instanceof ElggEntity) { |
||
1931 | $elgg['page_owner'] = $page_owner->toObject(); |
||
1932 | } |
||
1933 | |||
1934 | $user = elgg_get_logged_in_user_entity(); |
||
1935 | if ($user instanceof ElggUser) { |
||
1936 | $user_object = $user->toObject(); |
||
1937 | $user_object->admin = $user->isAdmin(); |
||
1938 | $elgg['session']['user'] = $user_object; |
||
1939 | } |
||
1940 | |||
1941 | return $elgg; |
||
1942 | } |
||
1943 | |||
1944 | /** |
||
1945 | * Render a view while the global viewtype is temporarily changed. This makes sure that |
||
1946 | * nested views use the same viewtype. |
||
1947 | * |
||
1948 | * @param string $view View name |
||
1949 | * @param array $vars View vars |
||
1950 | * @param string $viewtype Temporary viewtype ('' to leave current) |
||
1951 | * |
||
1952 | * @return mixed |
||
1953 | * @access private |
||
1954 | */ |
||
1955 | function _elgg_view_under_viewtype($view, $vars, $viewtype) { |
||
1956 | if ($viewtype) { |
||
1957 | $old = elgg_get_viewtype(); |
||
1958 | elgg_set_viewtype($viewtype); |
||
1959 | } |
||
1960 | |||
1961 | $ret = elgg_view($view, $vars); |
||
1962 | |||
1963 | if ($viewtype) { |
||
1964 | elgg_set_viewtype($old); |
||
1965 | } |
||
1966 | |||
1967 | return $ret; |
||
1968 | } |
||
1969 | |||
1970 | /** |
||
1971 | * Set lightbox config |
||
1972 | * |
||
1973 | * @param string $hook "elgg.data" |
||
1974 | * @param string $type "site" |
||
1975 | * @param array $return Data |
||
1976 | * @param array $params Hook params |
||
1977 | * @return array |
||
1978 | * @access private |
||
1979 | */ |
||
1980 | function _elgg_set_lightbox_config($hook, $type, $return, $params) { |
||
1981 | |||
1982 | $return['lightbox'] = [ |
||
1983 | 'current' => elgg_echo('js:lightbox:current', ['{current}', '{total}']), |
||
1984 | 'previous' => elgg_view_icon('caret-left'), |
||
1985 | 'next' => elgg_view_icon('caret-right'), |
||
1986 | 'close' => elgg_view_icon('times'), |
||
1987 | 'opacity' => 0.5, |
||
1988 | 'maxWidth' => '990px', |
||
1989 | 'maxHeight' => '990px', |
||
1990 | 'initialWidth' => '300px', |
||
1991 | 'initialHeight' => '300px', |
||
1992 | ]; |
||
1993 | |||
1994 | return $return; |
||
1995 | } |
||
1996 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.