Applied patch #411
[elgg.git] / lib / templates.php
blobc0dabd7edc1fa7e90352256658a3aa2ee0f98b3e
1 <?php
3 /*** NZVLE TODO
4 ***
5 *** + Break the html/css bits of the Default_Template into separate files
6 *** they mess up the code layout and indentation, and generally don't
7 *** belong here.
8 *** + Clean up and document the calling conventions -- get rid of $parameter
9 *** + the callbacks to template_variables_substitute are *evil* -- rework
10 ***
11 ***/
13 /***
14 *** Takes in the short name of a template and returns the comparable version
15 *** from the file system
16 *** @param string $shortname short name of template to convert to file version
17 ***/
18 function templates_shortname_to_file($shortname) {
19 $shortname = str_replace(" ","_",$shortname);
20 return $shortname;
23 /***
24 *** Takes in the directory name of a template and returns the comparable version
25 *** for use as a shortname to display
26 *** @param string $foldername folder name of template to convert to internal version
27 ***/
28 function templates_file_to_shortname($foldername) {
29 $foldername = str_replace("_"," ",$foldername);
30 return $foldername;
33 function default_template () {
35 global $CFG;
36 global $template;
37 global $template_definition;
38 $sitename = $CFG->sitename;
40 $run_result = '';
42 $template_definition[] = array(
43 'id' => 'css',
44 'name' => __gettext("Stylesheet"),
45 'description' => __gettext("The Cascading Style Sheet for the template."),
46 'glossary' => array(),
47 'display' => 1,
50 $template['css'] = file_get_contents($CFG->templatesroot . "Default_Template/css");
52 $template_definition[] = array(
53 'id' => 'pageshell',
54 'name' => __gettext("Page Shell"),
55 'description' => __gettext("The main page shell, including headers and footers."),
56 'glossary' => array(
57 '{{metatags}}' => __gettext("Page metatags (mandatory) - must be in the 'head' portion of the page"),
58 '{{title}}' => __gettext("Page title"),
59 '{{menu}}' => __gettext("Menu"),
60 '{{topmenu}}' => __gettext("Status menu"),
61 '{{mainbody}}' => __gettext("Main body"),
62 '{{sidebar}}' => __gettext("Sidebar")
66 $welcome = __gettext("Welcome"); // gettext variable
68 $template['pageshell'] = file_get_contents($CFG->templatesroot . "Default_Template/pageshell");
70 $template['frontpage_loggedout'] = file_get_contents($CFG->templatesroot . "Default_Template/frontpage_loggedout");
71 $template['frontpage_loggedin'] = file_get_contents($CFG->templatesroot . "Default_Template/frontpage_loggedin");
73 // REMOVED stylesheet (was old version and should not have been here)
74 // TODO: extract all Default_Template stuff from lib/templates.php
76 $template_definition[] = array(
77 'id' => 'contentholder',
78 'name' => __gettext("Content holder"),
79 'description' => __gettext("Contains the main content for a page (as opposed to the sidebar or the title)."),
80 'glossary' => array(
81 '{{title}}' => __gettext("The title"),
82 '{{submenu}}' => __gettext("The page submenu"),
83 '{{body}}' => __gettext("The body of the page")
85 );
87 $template['contentholder'] = <<< END
89 <div class="SectionContent">
91 <h1>{{title}}</h1>
92 {{submenu}}
93 </div>
94 {{body}}
96 END;
98 $template_definition[] = array(
99 'id' => 'ownerbox',
100 'name' => __gettext("Owner box"),
101 'description' => __gettext("A box containing a description of the owner of the current profile."),
102 'glossary' => array(
103 '{{name}}' => __gettext("The user's name"),
104 '{{profileurl}}' => __gettext("The URL of the user's profile page, including terminating slash"),
105 '{{usericon}}' => __gettext("The user's icon, if it exists"),
106 '{{tagline}}' => __gettext("A short blurb about the user"),
107 '{{usermenu}}' => __gettext("Links to friend / unfriend a user"),
108 '{{lmshosts}}' => __gettext("Links to any lms hosts the user is attached to"),
112 $tags = __gettext("Tags");
113 $resources = __gettext("Resources");
114 $template['ownerbox'] = <<< END
116 <div class="me">
117 <div style="float: left; width: 70px"><a href="{{profileurl}}">{{usericon}}</a></div>
118 <div style="margin-left: 75px; margin-top: 0px; padding-top: 0px; text-align: left" ><p>
119 <span class="userdetails">{{name}}<br /><a href="{{profileurl}}rss/">RSS</a> | <a href="{{profileurl}}tags/">$tags</a> | <a href="{{profileurl}}newsclient/">$resources</a></span></p>
120 <p>{{tagline}}</p>
121 <p>{{lmshosts}}</p>
122 <p style="margin-bottom: 3px" class="usermenu">{{usermenu}}</p>
123 </div>
124 </div>
126 END;
128 $template_definition[] = array(
129 'id' => 'infobox',
130 'name' => __gettext("Information Box"),
131 'description' => __gettext("A box containing a caption and some text, used extensively throughout the site. For example, the 'friends' box and most page bodies are info boxes. Of course, you can alter this template however you wish - it doesn't need to be an actual box."),
132 'glossary' => array(
133 '{{name}}' => __gettext("The title"),
134 '{{contents}}' => __gettext("The contents of the box")
137 $template['infobox'] = <<< END
139 <table class="infobox" width="100%">
140 <caption align="top">
141 {{name}}
142 </caption>
143 <tr>
144 <td>
145 {{contents}}
146 </td>
147 </tr>
148 </table><br />
149 END;
151 $template_definition[] = array(
152 'id' => 'messageshell',
153 'name' => __gettext("System message shell"),
154 'description' => __gettext("A list of system messages will be placed within the message shell."),
155 'glossary' => array(
156 '{{messages}}' => __gettext("The messages")
160 $template['messageshell'] = <<< END
162 <div id="js">{{messages}}</div><br />
164 END;
166 $template_definition[] = array(
167 'id' => 'messages',
168 'name' => __gettext("Individual system messages"),
169 'description' => __gettext("Each individual system message."),
170 'glossary' => array(
171 '{{message}}' => __gettext("The system message")
175 $template['messages'] = <<< END
178 {{message}}
179 </p>
181 END;
184 $template_definition[] = array(
185 'id' => 'menu',
186 'name' => __gettext("Main menu shell"),
187 'description' => __gettext("A list of main menu items will be placed within the menubar shell."),
188 'glossary' => array(
189 '{{menuitems}}' => __gettext("The menu items")
193 $template['menu'] = <<< END
195 {{menuitems}}
196 END;
198 $template_definition[] = array(
199 'id' => 'menuitem',
200 'name' => __gettext("Individual main menu item"),
201 'description' => __gettext("This is the template for each individual main menu item. A series of these is placed within the menubar shell template."),
202 'glossary' => array(
203 '{{location}}' => __gettext("The URL of the menu item"),
204 '{{name}}' => __gettext("The menu item's name")
208 $template['menuitem'] = <<< END
210 <li><a href="{{location}}">{{name}}</a></li>
212 END;
214 $template_definition[] = array(
215 'id' => 'selectedmenuitem',
216 'name' => __gettext("Selected individual main menu item"),
217 'description' => __gettext("This is the template for an individual main menu item if it is selected."),
218 'glossary' => array(
219 '{{location}}' => __gettext("The URL of the menu item"),
220 '{{name}}' => __gettext("The menu item's name")
224 $template['selectedmenuitem'] = <<< END
226 <li><a class="current" href="{{location}}">{{name}}</a></li>
228 END;
230 $template_definition[] = array(
231 'id' => 'submenu',
232 'name' => __gettext("Sub-menubar shell"),
233 'description' => __gettext("A list of sub-menu items will be placed within the menubar shell."),
234 'glossary' => array(
235 '{{submenuitems}}' => __gettext("The menu items")
239 $template['submenu'] = <<< END
241 <h3>
242 {{submenuitems}}
243 </h3>
244 END;
246 $template_definition[] = array(
247 'id' => 'submenuitem',
248 'name' => __gettext("Individual sub-menu item"),
249 'description' => __gettext("This is the template for each individual sub-menu item. A series of these is placed within the sub-menubar shell template."),
250 'glossary' => array(
251 '{{location}}' => __gettext("The URL of the menu item"),
252 '{{menu}}' => __gettext("The menu item's name")
256 $template['submenuitem'] = <<< END
258 <a href="{{location}}">{{name}}</a>&nbsp;|
260 END;
262 $template_definition[] = array(
263 'id' => 'topmenu',
264 'name' => __gettext("Status menubar shell"),
265 'description' => __gettext("A list of statusbar menu items will be placed within the status menubar shell."),
266 'glossary' => array(
267 '{{topmenuitems}}' => __gettext("The menu items")
271 $template['topmenu'] = <<< END
273 <div id="StatusRight">
274 {{topmenuitems}}
275 </div>
277 END;
279 $template_definition[] = array(
280 'id' => 'topmenuitem',
281 'name' => __gettext("Individual statusbar menu item"),
282 'description' => __gettext("This is the template for each individual statusbar menu item. A series of these is placed within the status menubar shell template."),
283 'glossary' => array(
284 '{{location}}' => __gettext("The URL of the menu item"),
285 '{{menu}}' => __gettext("The menu item's name")
289 $template['topmenuitem'] = <<< END
291 [<a href="{{location}}">{{name}}</a>]&nbsp;
293 END;
295 $template_definition[] = array(
296 'id' => 'databox',
297 'name' => __gettext("Data input box (two columns)"),
298 'description' => __gettext("This is mostly used whenever some input is taken from the user. For example, each of the fields in the profile edit screen is a data input box."),
299 'glossary' => array(
300 '{{name}}' => __gettext("The name for the data we're inputting"),
301 '{{column1}}' => __gettext("The first item of data"),
302 '{{column2}}' => __gettext("The second item of data")
306 $template['databox'] = <<< END
308 <div class="infobox">
309 <table width="95%" class="profiletable" align="center" style="margin-bottom: 3px">
310 <tr>
312 <td width="20%" class="fieldname" valign="top">
313 <p><b>{{name}}</b></p>
314 </td>
315 <td width="50%" valign="top">
316 <p>{{column1}}</p>
317 </td>
318 <td width="30%" valign="top">
319 <p>{{column2}}</p>
320 </td>
321 </tr>
322 </table>
323 </div>
325 END;
327 $template_definition[] = array(
328 'id' => 'databox1',
329 'name' => __gettext("Data input box (one column)"),
330 'description' => __gettext("A single-column version of the data box."),
331 'glossary' => array(
332 '{{name}}' => __gettext("The name of the data we're inputting"),
333 '{{column1}}' => __gettext("The data itself")
337 $template['databox1'] = <<< END
339 <div class="infobox">
340 <table width="95%" class="profiletable" align="center" style="margin-bottom: 3px">
341 <tr>
343 <td width="20%" class="fieldname" valign="top">
344 <p><b>{{name}}</b></p>
345 </td>
346 <td width="80%" valign="top">
347 <p>{{column1}}</p>
348 </td>
349 </tr>
350 </table>
351 </div>
353 END;
355 $template_definition[] = array(
356 'id' => 'databoxvertical',
357 'name' => __gettext("Data input box (vertical)"),
358 'description' => __gettext("A slightly different version of the data box, used on this edit page amongst other places."),
359 'glossary' => array(
360 '{{name}}' => __gettext("Name of the data we\'re inputting"),
361 '{{contents}}' => __gettext("The data itself")
365 $template['databoxvertical'] = <<< END
366 <div class="infobox">
367 <table width="95%" class="fileTable" align="center" style="margin-bottom: 3px">
368 <tr>
369 <td class="fieldname">
370 <p><b>{{name}}</b></p>
371 </td>
372 </tr>
373 <tr>
374 <td>
375 <p>{{contents}}</p>
376 </td>
377 </tr>
378 </table>
379 </div>
381 END;
382 return $run_result;
385 function templates_main () {
387 global $PAGE;
389 $run_result = '';
392 * Templates unit
395 // Load default values
396 $function['init'][] = path . "units/templates/default_template.php";
398 // Actions
399 $function['templates:init'][] = path . "units/templates/template_actions.php";
401 // Draw template (returns HTML as opposed to echoing it straight to the screen)
402 $function['templates:draw'][] = path . "units/templates/template_draw.php";
404 // Function to substitute variables within a template, used in templates:draw
405 $function['templates:variables:substitute'][] = path . "units/templates/variables_substitute.php";
407 // Function to draw the page, once supplied with a main body and title
408 $function['templates:draw:page'][] = path . "units/templates/page_draw.php";
410 // Function to display a list of templates
411 $function['templates:view'][] = path . "units/templates/templates_view.php";
412 $function['templates:preview'][] = path . "units/templates/templates_preview.php";
414 // Function to display input fields for template editing
415 $function['templates:edit'][] = path . "units/templates/templates_edit.php";
417 // Function to allow the user to create a new template
418 $function['templates:add'][] = path . "units/templates/templates_add.php";
420 if ($context == "account") {
421 $PAGE->menu_sub[] = array( 'name' => 'template:edit',
422 'html' => templates_draw(array( 'context' => 'submenuitem',
423 'name' => __gettext("Change theme"),
424 'location' => url . '_templates/')));
427 return $run_result;
430 function templates_page_setup (){
432 global $PAGE;
433 global $CFG;
435 if (!empty($PAGE->setupdone)) {
436 return false; // don't run twice
439 $PAGE->setupdone = true; // leave your mark
442 // Populate $PAGE with links for non-module core code
445 if (isadmin()) {
446 $PAGE->menu_top [] = array( 'name' => 'admin',
447 //'html' => a_href("{$CFG->wwwroot}_admin/",
448 // "Administration"));
449 'html' => "<li><a href=\"" . $CFG->wwwroot . "mod/admin/\">" . __gettext("Administration") . "</a></li>");
452 if (logged_on) {
453 $PAGE->menu_top[] = array(
454 'name' => 'userdetails',
455 //'html' => a_href("{$CFG->wwwroot}_userdetails/",
456 // "Account settings"));
457 'html' => "<li><a href=\"" . $CFG->wwwroot . "_userdetails/\">" . __gettext("Account settings") . "</a></li>");
459 $PAGE->menu_top[] = array(
460 'name' => 'logoff',
461 //'html' => a_href("{$CFG->wwwroot}login/logout.php",
462 // "Log off"));
463 'html' => "<li><a href=\"" . $CFG->wwwroot . "login/logout.php\">" . __gettext("Log off") . "</a></li>");
468 // Give a chance to all registered modules
470 if ($allmods = get_list_of_plugins('mod') ) {
471 foreach ($allmods as $mod) {
472 $mod_pagesetup = $mod . '_pagesetup';
473 if (function_exists($mod_pagesetup)) {
474 $mod_pagesetup();
475 } else {
476 notify("Function $mod_pagesetup doesn't exist!");
482 function templates_page_draw ($param) {
483 // Draws the page, given a title and a main body (parameters[0] and [1]).
484 $title = $param[0];
485 $mainbody = $param[1];
487 $run_result = '';
489 global $messages;
491 ////
492 //// Prepare things for the module run
493 //// populating $PAGE as required
494 ////
495 if (empty($PAGE->setupdone)) {
496 templates_page_setup();
499 $messageshell = "";
500 if (isset($messages) && sizeof($messages) > 0) {
501 foreach($messages as $message) {
502 $messageshell .=templates_draw(array(
503 'context' => 'messages',
504 'message' => $message
508 $messageshell =templates_draw(array(
509 'context' => 'messageshell',
510 'messages' => $messageshell
515 // If $parameter[2] is set, we'll substitute it for the
516 // sidebar
517 if (isset($param[2])) {
518 $sidebarhtml = $param[2];
519 } else {
520 $sidebarhtml = run("display:sidebar");
523 $run_result .= templates_draw(array(
524 'context' => 'pageshell',
525 'title' => htmlspecialchars($title, ENT_COMPAT, 'utf-8'),
526 'menu' => displaymenu(),
527 'submenu' => displaymenu_sub(),
528 'top' => displaymenu_top(),
529 'sidebar' => $sidebarhtml,
530 'mainbody' => $mainbody,
531 'messageshell' => $messageshell
534 return $run_result;
537 function templates_actions() {
539 global $CFG,$USER,$db;
541 // Actions
543 global $template, $messages, $CFG;
545 $action = optional_param('action');
546 if (!logged_on) {
547 return false;
550 $run_result = '';
552 switch ($action) {
553 case "templates:select":
554 $id = optional_param('selected_template');
555 if (substr($id, 0, 2) == "db") {
556 $template_id = (int) substr($id,2);
557 $exists = record_exists_sql('SELECT ident, shortname FROM '.$CFG->prefix.'templates WHERE ident = '.$template_id.' AND (owner = '.$USER->ident ." OR public='yes')");
558 } else {
559 $exists = file_exists($CFG->templatesroot . templates_shortname_to_file($id));
561 if ($exists) {
562 $affected_areas = optional_param('affected_areas',0,PARAM_INT);
563 if(is_array($affected_areas)) {
564 foreach($affected_areas as $index => $value) {
565 //TODO - check security
566 set_field('users','template_name',$id,'ident',$value);
568 $messages[] = __gettext("The templates have been changed according to your choices.");
569 } else {
570 $messages[] = __gettext("No changes made as no area of change was selected!");
573 break;
576 case "templates:save":
577 $templatearray = optional_param('template','','');
578 $id = optional_param('save_template_id',0,PARAM_INT);
579 $templatetitle = trim(optional_param('templatetitle'));
580 if (!empty($templatearray) && !empty($id) && !empty($templatetitle)) {
581 unset($_SESSION['template_element_cache'][$id]);
582 $exists = record_exists('templates','ident',$id,'owner',$USER->ident);
583 if ($exists) {
584 set_field('templates','name',$templatetitle,'ident',$id);
585 delete_records('template_elements','template_id',$id);
586 foreach($templatearray as $name => $content) {
587 //TODO Fix this with PARAM_CLEANHTML or similar
588 $cleanname = trim($name);
589 $cleancontent = trim($content);
590 if ($content != "" && $content != $template[$name]) {
591 $te = new StdClass;
592 $te->name = $cleanname;
593 $te->content = $cleancontent;
594 $te->template_id = $id;
595 insert_record('template_elements',$te);
598 $messages[] = __gettext("Your template has been updated.");
601 break;
604 case "deletetemplate":
605 $id = optional_param('delete_template_id',0,PARAM_INT);
606 unset($_SESSION['template_element_cache'][$id]);
607 $exists = record_exists('templates','ident',$id,'owner',$USER->ident);
608 if ($exists) {
609 //$db->execute('UPDATE '.$CFG->prefix.'users SET template_id = -1 WHERE template_id = '.$id);
610 set_field('users', 'template_id', -1, 'template_id', $id);
611 delete_records('template_elements','template_id',$id);
612 delete_records('templates','ident',$id);
613 $messages[] = __gettext("Your template was deleted.");
615 break;
618 case "templates:create":
619 $based_on = optional_param('template_based_on');
620 $name = trim(optional_param('new_template_name'));
621 if (empty($CFG->disable_usertemplates) && !empty($name)) {
622 $t = new StdClass;
623 $t->name = $name;
624 $t->public = 'no';
625 $t->owner = $USER->ident;
626 $new_template_id = insert_record('templates',$t);
627 $t->shortname = 'db'.$new_template_id;
628 $t->ident = $new_template_id;
629 update_record('templates',$t);
630 foreach(array('pageshell','css') as $template_element) {
631 if ($result = get_template_element($based_on, $template_element)) {
632 $element = new stdClass;
633 $element->template_id = $new_template_id;
634 $element->content = $result->content;
635 $element->name = $template_element;
636 insert_record('template_elements',$element);
640 break;
642 return $run_result;
645 /// NOTE: this function takes a named array as single parameter
646 function templates_draw ($parameter) {
648 // Draw a page element using a specified template (or, if the template is -1, the default)
649 // $parameter['template'] = the template ID, $parameter['element'] = the template element,
650 // all other $parameter[n] = template elements
652 // Initialise global template variable, which contains the Default_Template
653 global $template;
655 // Initialise global template ID variable, which contains the template ID we're using
656 global $template_name;
657 global $page_owner;
658 global $CFG;
660 global $page_template_cache;
662 $run_result = '';
664 if ($parameter['context'] === 'topmenuitem') {
665 // error_log("templates_draw pcontext " . print_r($parameter,1));
667 // Get template details
668 if (!isset($template_name)) {
669 if (!isset($page_owner) || $page_owner == -1) {
670 $template_name = "Default_Template";
671 } else {
672 if (!$template_name = user_info('template_name',$page_owner)) {
673 $template_name = "Default_Template";
678 // Template ID override
679 $t = optional_param('template_preview');
680 if (!empty($t)) {
681 $template_name = $t;
684 // TODO: Load templates on demand with backward compatibility
685 templates_load_context($parameter['context']);
687 // Grab the template content
688 if ($template_name == "Default_Template" || ($parameter['context'] != "css" && $parameter['context'] != "pageshell")) {
689 $template_element = $template[$parameter['context']];
690 } else {
691 if (!isset($page_template_cache[$parameter['context']])) {
692 if ($result = get_template_element($template_name, $parameter['context'])) {
693 $page_template_cache[$parameter['context']] = $result;
694 } else {
695 $page_template_cache[$parameter['context']] = $template[$parameter['context']];
697 } else {
698 $result = $page_template_cache[$parameter['context']];
700 if (!empty($result)) {
701 $template_element = $result->content;
702 } else {
703 $template_element = $template[$parameter['context']];
707 if (!empty($CFG->templates->variables_substitute) && !empty($CFG->templates->variables_substitute[$parameter['context']])) {
708 if (is_array($CFG->templates->variables_substitute[$parameter['context']])) {
709 foreach ($CFG->templates->variables_substitute[$parameter['context']] as $sub_function) {
710 $template_element .= $sub_function($vars);
712 } elseif (is_callable($CFG->templates->variables_substitute[$parameter['context']])) {
713 $template_element .= $CFG->templates->variables_substitute[$parameter['context']]($vars);
717 if ($parameter['context'] === 'topmenuitem') {
718 // error_log("templates_draw pcontext " . print_r($template_element));
721 // Substitute elements
723 $functionbody = "
724 \$passed = array(".var_export($parameter,true).",\$matches[1], '" . $template_name . "');
725 return templates_variables_substitute(\$passed);
728 // $template_element = templates_variables_substitute(array($parameter,$template_element));
729 $body = preg_replace_callback("/\{\{([A-Za-z_0-9: ]*)\}\}/i",create_function('$matches',$functionbody),$template_element);
731 $run_result = $body;
732 return $run_result;
735 /***
736 *** Draws a form to create a new template based on one of the existing choices.
737 ***/
738 function templates_add () {
739 global $USER;
742 // Create a new template
743 $header = __gettext("Create theme"); // gettext variable
744 $desc = __gettext("Here you can create your own themes based on one of the existing public themes. Just select which public theme you would like to alter and then create your own. You will now have edit privilages."); // gettext variable
746 $panel = <<< END
748 <h2>$header</h2>
749 <p>$desc</p>
750 <form action="index.php" method="post">
752 END;
754 $panel .= <<< END
756 END;
758 $panel .=templates_draw(array(
759 'context' => 'databox1',
760 'name' => __gettext("Theme name"),
761 'column1' => display_input_field(array("new_template_name","","text"))
765 $default = __gettext("Default Template"); // gettext variable
766 $templates_list = templates_list();
767 $column1 = "<select name=\"template_based_on\">";
768 foreach($templates_list as $template) {
769 $name = __gettext($template['name']);
770 $column1 .= "<option value=\"".$template['name']."\"";
771 if ($template['name'] == "Default Template") {
772 $column1 .= " selected=\"selected\"";
774 $column1 .= ">" . $name . "</option>";
777 $column1 .= <<< END
778 </select>
779 END;
781 $panel .=templates_draw(array(
782 'context' => 'databox1',
783 'name' => __gettext("Based on"),
784 'column1' => $column1
788 $buttonValue = __gettext("Create Theme"); // gettext variable
789 $panel .= <<< END
792 <input type="hidden" name="action" value="templates:create" />
793 <input type="submit" value="$buttonValue" />
794 </p>
796 </form>
798 END;
800 return $panel;
803 function templates_edit () {
806 global $template;
807 global $template_definition;
808 global $USER;
810 if (!isset($parameter)) {
811 // Get template details
812 if (!$template_name = user_info('template_name',$USER->ident)) {
813 $template_name = "Default_Template";
815 } else {
816 if (!is_array($parameter)) {
817 $template_name = trim($parameter);
818 } else {
819 $template_name = "Default_Template";
823 // Grab title, see if we can edit the template
824 $editable = 0;
825 if ($template_name == "Default_Template") {
826 $templatetitle = __gettext("Default Theme");
827 } else {
828 if ($templatestuff = get_record('templates','shortname',$template_name)) {
829 $templatetitle = $templatestuff->name;
830 if ($templatestuff->owner == $USER->ident) {
831 $editable = 1;
833 if (($templatestuff->owner != $USER->ident) && ($templatestuff->public != 'yes')) {
834 $template_name = 'Default_Template';
839 // Grab the template content
840 if ($template_name == "Default_Template") {
841 $current_template = $template;
842 } else {
844 if (substr($template_name, 0, 2) == "db") {
845 $template_id = (int) substr($template_name,2);
846 $result = get_record('template_elements','template_id',$template_id,'name',$element_name);
847 if ($elements = get_records('template_elements','template_id',$template_id)) {
848 foreach($result as $element) {
849 $current_template[$element->name] = $element->content;
851 } else {
852 $current_template = $template;
854 } else {
855 foreach(array('pageshell','css') as $element_name) {
856 $template_file = $CFG->templatesroot . templates_shortname_to_file($template_name) . '/' . $element_name;
857 if ($element_content = file_get_contents($template_file)) {
858 $current_template[$element_name] = $element_content;
864 $run_result .= <<< END
866 <form action="" method="post">
868 END;
870 $run_result .= templates_draw(array(
871 'context' => 'databoxvertical',
872 'name' => __gettext("Theme Name"),
873 'contents' => display_input_field(array("templatetitle",$templatetitle,"text"))
877 foreach($template_definition as $element) {
879 $name = "<b>" . $element['name'] . "</b><br /><i>" . $element['description'] . "</i>";
880 $glossary = __gettext("Glossary"); // gettext variable
882 if (is_array($element['glossary']) && sizeof($element['glossary']) > 0) {
883 $column1 = "<b>$glossary</b><br />";
884 foreach($element['glossary'] as $gloss_id => $gloss_descr) {
885 $column1 .= $gloss_id . " -- " . $gloss_descr . "<br />";
887 } else {
888 $column1 = "";
891 if ($current_template[$element['id']] == "" || !isset($current_template[$element['id']])) {
892 $current_template[$element['id']] = $template[$element['id']];
895 $column2 = display_input_field(array("template[" . $element['id'] . "]",$current_template[$element['id']],"longtext"));
897 $run_result .=templates_draw(array(
898 'context' => 'databox',
899 'name' => $name,
900 'column2' => $column1,
901 'column1' => $column2
905 $run_result .=templates_draw(array(
906 'context' => 'databoxvertical',
907 'name' => $name,
908 'contents' => $column1 . "<br />" . $column2
915 if ($editable) {
916 $save = __gettext("Save"); // gettext variable
917 $run_result .= <<< END
919 <p align="center">
920 <input type="hidden" name="action" value="templates:save" />
921 <input type="hidden" name="save_template_id" value="$template_id" />
922 <input type="submit" value="$save" />
923 </p>
925 END;
926 } else {
927 $noEdit = __gettext("You may not edit this theme. To create a new, editable theme based on the default, go to <a href=\"index.php\">the main themes page</a>."); // gettext variable
928 $run_result .= <<< END
931 $noEdit
932 </p>
934 END;
936 $run_result .= <<< END
938 </form>
940 END;
941 return $run_result;
944 function templates_preview () {
946 global $CFG;
947 $run_result = '';
949 // Preview template
951 // Basic page elements
953 $name = "Basic page elements";
954 $heading1 = __gettext("Heading one"); // gettext variable
955 $heading2 = __gettext("Heading two"); // gettext variable
956 $bulletList = __gettext("A bullet list"); // gettext variable
957 $heading3 = __gettext("Heading three"); // gettext variable
958 $numberedList = __gettext("A numbered list"); // gettext variable
959 $body = <<< END
961 <img src="{$CFG->wwwroot}mod/template/images/leaves.jpg" width="300" height="225" alt="A test image" align="right" />
962 <h1>$heading1</h1>
963 <p>Paragraph text</p>
964 <h2>$heading2</h2>
965 <ul>
966 <li>$bulletList</li>
967 </ul>
968 <h3>$heading3</h3>
969 <ol>
970 <li>$numberedList</li>
971 </ol>
973 END;
975 $run_result .= templates_draw(array(
976 'context' => 'contentholder',
977 'title' => $name,
978 'body' => $body
982 // Form elements
984 $name = "Data input";
986 $body =templates_draw(array(
987 'context' => 'databox',
988 'name' => __gettext("Some text input"),
989 'column1' => display_input_field(array("blank","","text")),
990 'column2' => run("display:access_level_select",array("blank","PUBLIC"))
993 $body .=templates_draw(array(
994 'context' => 'databox1',
995 'name' => __gettext("Some longer text input"),
996 'column1' => display_input_field(array("blank","","longtext"))
999 $body .=templates_draw(array(
1000 'context' => 'databoxvertical',
1001 'name' => __gettext("Further text input"),
1002 'contents' => display_input_field(array("blank","","longtext")) . "<br />" . display_input_field(array("blank","","text")) . "<br /><input type='button' value='Button' />"
1006 $run_result .=templates_draw(array(
1007 'context' => 'contentholder',
1008 'title' => $name,
1009 'body' => $body,
1010 'submenu' => ''
1013 return $run_result;
1016 /***
1017 *** Returns a list of templates as an array.
1018 ***/
1019 function templates_list() {
1021 global $CFG;
1022 $template_list = array();
1023 if ($templates = get_list_of_plugins($CFG->templatesroot,'theme_master')) {
1024 foreach($templates as $template) {
1025 $template_list[] = array(
1026 'name' => templates_file_to_shortname($template),
1027 'id' => NULL,
1028 'shortname' => $template
1032 if ($templates = get_records('templates','public','yes')) {
1033 foreach($templates as $template) {
1034 $template_list[] = array(
1035 'name' => $template->name,
1036 'id' => $template->ident,
1037 'shortname' => $template->shortname
1041 return $template_list;
1044 function templates_view () {
1045 global $USER, $CFG;
1046 $run_result = "";
1048 $user_template = user_info('template_name',$USER->ident);
1049 $sitename = sitename;
1050 $title = __gettext("Select / Create / Edit Themes"); // gettext variable
1051 $header = __gettext("Public Themes"); // gettext variable
1052 $desc = sprintf(__gettext("The following are public themes that you can use to change the way your %s looks - these do not change the content only the appearance. Check the preview and then select the one you want. If you wish you can adapt one of these using the 'create theme' option below."), $sitename); // gettext variable
1053 $panel = <<< END
1055 <h2>$title</h2>
1056 <form action="" method="post">
1057 <h3>
1058 $header
1059 </h3>
1061 $desc
1062 </p>
1064 END;
1066 $template_list[] = array(
1067 'name' => __gettext("Default Theme"),
1068 'shortname' => "Default_Template",
1069 'id' => -1
1072 $template_list = templates_list();
1073 foreach($template_list as $template) {
1074 if ($template['name'] == "Default Template") {
1075 $template['name'] = __gettext("Default Template");
1077 $name = "<input type='radio' name='selected_template' value='".$template['shortname']."' ";
1078 if ($template['shortname'] == $user_template) {
1079 $name .= "checked=\"checked\"";
1081 $name .=" /> ";
1082 $column1 = "<b>" . $template['name'] . "</b>";
1083 $column2 = "<a href=\"".url."_templates/preview.php?template_preview=".$template['shortname']."\" target=\"preview\">" . __gettext("Preview") . "</a>";
1084 $panel .=templates_draw(array(
1085 'context' => 'adminTable',
1086 'name' => $name,
1087 'column1' => $column1,
1088 'column2' => $column2
1093 $templates = get_records('templates','owner',$USER->ident);
1094 $header2 = __gettext("Personal themes"); // gettext variable
1095 $desc2 = __gettext("These are themes that you have created. You can edit and delete these. These theme(s) only control actual look and feel - you cannot change any content here. To change any of your content you need to use the other menu options such as: edit profile, update weblog etc."); // gettext variable
1097 if (is_array($templates) && sizeof($templates) > 0) {
1098 $panel .= <<< END
1099 <h3>
1100 $header2
1101 </h3>
1103 $desc2
1104 </p>
1106 END;
1108 foreach($templates as $template) {
1109 $name = "<input type='radio' name='selected_template' value='db".$template->ident."'";
1110 if ($template->shortname == $user_template) {
1111 $name .= " checked=\"checked\"";
1113 $name .=" /> ";
1114 $column1 = "<b>" . $template->name . "</b>";
1115 $column2 = "<a href=\"".url."_templates/preview.php?template_preview=".$template->shortname."\" target=\"preview\">" . __gettext("Preview") . "</a>";
1117 $column2 .= " | <a href=\"".url."_templates/edit.php?id=".$template->ident."\" >". __gettext("Edit") ."</a>";
1118 $column2 .= " | <a href=\"".url."_templates/?action=deletetemplate&amp;delete_template_id=".$template->ident."\" onclick=\"return confirm('" . __gettext("Are you sure you want to permanently remove this template?") . "')\">" . __gettext("Delete") . "</a>";
1119 $panel .=templates_draw(array(
1120 'context' => 'adminTable',
1121 'name' => $name,
1122 'column1' => $column1,
1123 'column2' => $column2
1129 $ownerCommunities = get_records('users','owner',$USER->ident);
1130 $header3 = __gettext("Change templates");
1131 $decs3 = __gettext("The selected changes will affect:");
1133 $panel .= <<< END
1134 <br />
1135 <h2>
1136 $header3
1137 </h2>
1139 $decs3
1140 </p>
1141 END;
1143 $name = "<input type='checkbox' name='affected_areas[]' value='".$USER->ident."' checked=\"checked\" />";
1144 $column1 = "<h4>User page</h4>";
1145 $column2 = "<h4>". __gettext("Your personal space") ."</h4>";
1146 $panel .= templates_draw(array(
1147 'context' => 'adminTable',
1148 'name' => $name,
1149 'column1' => $column1,
1150 'column2' => $column2
1154 if(!empty($ownerCommunities)) {
1155 foreach($ownerCommunities as $ownerCommunity) {
1156 $name = "<input type='checkbox' name='affected_areas[]' value='".$ownerCommunity->ident."' />";
1157 $column1 = "<h4>".stripslashes($ownerCommunity->name)."</h4>";
1158 $column2 = "<h4>".__gettext("Community: ") . stripslashes($ownerCommunity->name)."</h4>";
1159 $panel .= templates_draw(array(
1160 'context' => 'adminTable',
1161 'name' => $name,
1162 'column1' => $column1,
1163 'column2' => $column2
1170 $submitValue = __gettext("Select new theme"); // gettext variable
1171 $panel .= <<< END
1174 <input type="submit" value="$submitValue" />
1175 <input type="hidden" name="action" value="templates:select" />
1176 </p>
1178 </form>
1180 END;
1182 $run_result .= $panel;
1183 return $run_result;
1186 function templates_variables_substitute ($param) {
1188 global $CFG;
1190 $variables = $param[0];
1191 $template_variable = $param[1];
1193 $run_result = '';
1195 // Substitute variables in templates:
1196 // where {{variablename}} is found in the template, this function is passed
1197 // "variablename" and returns the proper variable
1199 global $menubar;
1200 global $submenubar;
1201 global $metatags;
1202 global $PAGE;
1203 global $template_id;
1204 global $template_name;
1205 global $db;
1207 //error_log("tvs " . print_r($template_variable,1));
1209 $result = "";
1210 if (isset($variables[$template_variable])) {
1211 $result .= $variables[$template_variable];
1212 } else {
1213 $vars = array();
1214 if (substr_count($template_variable,":") > 0) {
1215 $vars = explode(":",$template_variable);
1216 $template_variable = $vars[0];
1218 switch($template_variable) {
1220 case "username":
1221 if (logged_on) {
1222 $result = $_SESSION['username'];
1223 } else {
1224 $result = __gettext("Guest");
1226 break;
1227 case "usericonid":
1228 if (logged_on) {
1229 $result = user_info("icon",$_SESSION['userid']);
1230 } else {
1231 $result = 0;
1233 break;
1234 case "name":
1235 if (logged_on) {
1236 $result = htmlspecialchars($_SESSION['name'], ENT_COMPAT, 'utf-8');
1237 } else {
1238 $result = __gettext("Guest");
1240 break;
1241 case "userfullname":
1242 if (logged_on) {
1243 $result = __gettext("Welcome") . " " . htmlspecialchars($_SESSION['name'], ENT_COMPAT, 'utf-8');
1244 } else {
1245 $result = __gettext("Welcome") . " " . __gettext("Guest") . " [<a href=\"".url."login/index.php\">" . __gettext("Log in") . "</a>]";
1247 break;
1248 case "menu":
1249 if (logged_on) {
1250 $result = templates_draw(array(
1251 'menuitems' => menu_join('', $PAGE->menu),
1252 'context' => 'menu'
1255 break;
1257 case "submenu":
1258 $result = templates_draw(array(
1259 'submenuitems' => menu_join('&nbsp;|&nbsp;', $PAGE->menu_sub),
1260 'context' => 'submenu'
1262 break;
1264 case "topmenu":
1265 $result = templates_draw(array(
1266 'topmenuitems' => menu_join('', $PAGE->menu_top),
1267 'context' => 'topmenu'
1269 break;
1271 case "url":
1272 $result = url;
1273 break;
1275 case "sitename":
1276 $result = $CFG->sitename;
1277 break;
1279 case "tagline":
1280 $result = $CFG->tagline;
1281 break;
1283 case "metatags":
1284 if (!empty($template_name)) {
1285 // use a defined style
1286 $result = '<link href="' . $CFG->wwwroot . '_templates/css/' . $template_name. '" rel="stylesheet" type="text/css" />' . "\n";
1287 } else {
1288 // use whatever's in $template['css']
1289 $result = "<style type=\"text/css\">\n"
1290 . templates_draw(array(
1291 'template' => $template_name,
1292 'context' => 'css'
1295 . "\n</style>\n";
1297 $result .= $metatags;
1298 break;
1300 case 'perf':
1301 $perf = get_performance_info();
1302 if (defined('ELGG_PERFTOLOG')) {
1303 error_log("PERF: " . $perf['txt']);
1305 if (defined('ELGG_PERFTOFOOT') || $CFG->debug > 7 || $CFG->perfdebug > 7) {
1306 $result = $perf['html'];
1309 break;
1311 case 'randomusers':
1312 $result = "";
1314 if (isset($vars[1])) {
1315 $vars[1] = (int) $vars[1];
1316 } else {
1317 $vars[1] = 3;
1320 if ($users = get_records_sql("SELECT DISTINCT u.*,i.filename AS iconfile, ".$db->random." as rand
1321 FROM ".$CFG->prefix."profile_data t JOIN ".$CFG->prefix."users u ON u.ident = t.owner
1322 LEFT JOIN ".$CFG->prefix."icons i ON i.ident = u.icon
1323 WHERE t.name IN (?,?,?) AND u.icon != ? AND t.access = ? AND u.user_type = ?
1324 ORDER BY rand LIMIT " . $vars[1],array('biography','minibio','interests',-1,'PUBLIC','person'))) {
1325 $usercount = 0;
1326 foreach($users as $user) {
1327 if ($usercount > 0) {
1328 $result .= ", ";
1329 } else {
1330 $result .= " ";
1332 $result .= "<a href=\"" . $CFG->wwwroot . $user->username . "/\">" . $user->name . "</a>";
1333 $usercount++;
1335 } else {
1336 $result .= __gettext("Sorry, no users have filled in their profiles yet.");
1339 break;
1340 case 'people':
1341 $result = "";
1342 if (isset($vars[1])) {
1343 $vars[1] = $db->qstr($vars[1]);
1344 } else {
1345 $vars[1] = "'interests'";
1348 if (isset($vars[2])) {
1349 $vars[2] = $db->qstr($vars[2]);
1350 } else {
1351 $vars[2] = "'foo'";
1354 if (isset($vars[3])) {
1355 $vars[3] = (int) $vars[3];
1356 } else {
1357 $vars[3] = 5;
1360 $users = get_records_sql("SELECT users.*, icons.filename as iconfile, icons.ident as iconid FROM ".$CFG->prefix."tags LEFT JOIN ".$CFG->prefix."users ON users.ident = tags.owner left join ".$CFG->prefix."icons on icons.ident = users.icon WHERE tags.tag = ".$vars[2]." AND tags.tagtype = ".$vars[1]." AND users.icon != -1 AND tags.access = 'PUBLIC' and users.user_type = 'person' ORDER BY rand( ) LIMIT " . $vars[3]);
1361 if (sizeof($users) > 0 && is_array($users)) {
1363 $result .= <<< END
1364 <table width="550px" border="0" cellpadding="0" cellspacing="0">
1365 <tr>
1366 END;
1368 foreach($users as $user) {
1369 $icon_html = user_icon_html($user->ident,67);
1370 $result .= <<< END
1372 <td align="center">
1373 <div class="image_holder">
1374 <a href="{$CFG->wwwroot}{$user->username}/">{$icon_html}</a>
1375 </div>
1376 <div class="userdetails">
1377 <p><a href="{$CFG->wwwroot}{$user->username}/">{$user->name}</a></p>
1378 </div>
1379 END;
1382 $result .= <<< END
1383 <tr>
1384 </table>
1385 END;
1388 break;
1390 case "toptags":
1391 if (isset($vars[1])) {
1392 $vars[1] = $db->qstr($vars[1]);
1393 } else {
1394 $vars[1] = "'town'";
1396 if ($tags = get_records_sql("SELECT tag, count(ident) as numtags FROM `".$CFG->prefix."tags` WHERE access = 'public' and tagtype=".$vars[1]." group by tag order by numtags desc limit 20")) {
1397 $tag_count = 0;
1398 foreach($tags as $tag) {
1399 $result .= "<a href=\"".url."tag/".urlencode(htmlspecialchars(strtolower($tag->tag), ENT_COMPAT, 'utf-8'))."\" title=\"".htmlspecialchars($tag->tag, ENT_COMPAT, 'utf-8')." (" .$tag->numtags. ")\">";
1400 $result .= $tag->tag . "</a>";
1401 if ($tag_count < sizeof($tags) - 1) {
1402 $result .= ", ";
1404 $tag_count++;
1408 break;
1410 case "populartags":
1411 $result = "";
1412 if ($tags = get_records_sql("SELECT tag, count(ident) as numtags FROM `".$CFG->prefix."tags` WHERE access = 'public' and tag!='' group by tag having numtags > 1 order by ident desc limit 20")) {
1413 $max = 0;
1414 foreach($tags as $tag) {
1415 if ($tag->numtags > $max) {
1416 $max = $tag->numtags;
1420 $tag_count = 0;
1421 foreach($tags as $tag) {
1423 if ($max > 1) {
1424 $size = round((log($tag->numtags) / log($max)) * 300);
1425 } else {
1426 $size = 100;
1429 $result .= "<a href=\"".url."tag/".urlencode(htmlspecialchars(strtolower($tag->tag), ENT_COMPAT, 'utf-8'))."\" style=\"font-size: $size%\" title=\"".htmlspecialchars($tag->tag, ENT_COMPAT, 'utf-8')." (" .$tag->numtags. ")\">";
1430 $result .= $tag->tag . "</a>";
1431 if ($tag_count < sizeof($tags) - 1) {
1432 $result .= ", ";
1434 $tag_count++;
1438 break;
1439 default:
1440 break;
1444 if (!empty($CFG->templates->variables_substitute) && !empty($CFG->templates->variables_substitute[$template_variable])) {
1445 if (is_array($CFG->templates->variables_substitute[$template_variable])) {
1446 foreach ($CFG->templates->variables_substitute[$template_variable] as $sub_function) {
1447 $result .= $sub_function($vars);
1449 } elseif (is_callable($CFG->templates->variables_substitute[$template_variable])) {
1450 $result .= $CFG->templates->variables_substitute[$template_variable]($vars);
1453 $run_result .= $result;
1454 return $run_result;
1457 /***
1458 *** Fetches the template elements from disk or db.
1459 *** If $template_name starts with 'db', it will assume the rest of the name
1460 *** is a database ident. Otherwise, it will
1461 ***/
1462 function get_template_element ($template_name, $element_name) {
1463 global $CFG;
1464 static $template_cache;
1466 // $template_name = strtolower(clean_param($template_name, PARAM_ALPHANUM));
1467 $result = false;
1468 if ($CFG->templatestore === 'db') {
1469 if (substr($template_name, 0, 2) == "db") {
1470 $template_id = (int) substr($template_name,2);
1471 $result = get_record('template_elements','template_id',$template_id,'name',$element_name);
1472 } else {
1473 $template_file = $CFG->templatesroot . templates_shortname_to_file($template_name) . '/' . $element_name;
1474 if ($element_content = @file_get_contents($template_file)) {
1475 $result = new StdClass;
1476 $result->content = $element_content;
1477 $result->ident = NULL;
1478 $result->name = $element_name;
1479 $result->shortname = $template_name;
1482 } else {
1483 // $template_name = get_field('templates', 'name', 'ident', $template_id);
1484 // $template_name = strtolower(clean_param($template_name, PARAM_ALPHANUM));
1485 $template_file = $CFG->templatesroot . templates_shortname_to_file($template_name) . '/' . $element_name;
1487 if ($element_content = @file_get_contents($template_file)) {
1488 $result = new StdClass;
1489 $result->content = $element_content;
1490 $result->ident = $template_id;
1491 $result->name = $element_name;
1492 $result->shortname = $template_name;
1495 return $result;
1498 /*** menu_join()
1499 *** performs a join on one of
1500 *** the $PAGE->menu* variables
1501 *** returns HTML
1502 ***/
1503 function menu_join ($separator, $menuarray) {
1504 $html = array();
1505 foreach ($menuarray as $entry) {
1506 array_push($html, $entry['html']);
1508 return join($separator, $html);
1512 * Adds new template context
1513 * @param string $context Context identificator
1514 * @param string $tpl Template path relative to dirroot or inline template
1515 * @param bool $is_file Template is file or inline
1516 * @param bool $override To override existing context
1518 function templates_add_context($context, $tpl, $is_file=true, $override=false) {
1519 // TODO: this function should go int mod's?
1520 global $template, $template_files, $CFG;
1522 if (!isset($template)) $template = array();
1523 if (!isset($template_files)) $template_files = array();
1525 if (!empty($context)) {
1526 // clean file path string
1527 if ($is_file) {
1528 // FIXME: backward compatiblity, allow templatesroot full path
1529 if (substr_count($tpl, $CFG->templatesroot) > 0) {
1530 $file_path = $tpl;
1531 } else {
1532 //$file_path = $CFG->dirroot . clean_filename($tpl);
1533 // clean_filename replaces / directory separator
1534 $file_path = $CFG->dirroot . $tpl;
1538 if ($is_file) {
1539 if ($override) {
1540 $template_files[$context] = array();
1543 $template_files[$context][] = $file_path;
1544 } else {
1545 // inline template, backwards compatibility
1546 if (!$override && isset($template[$context])) {
1547 // append to existing context
1548 $template[$context] .= $tpl;
1549 } else {
1550 $template[$context] = $tpl;
1557 * Load context if template is file
1558 * @param string $context Context identificator
1560 function templates_load_context($context) {
1561 // TOOD: review check
1562 // currently check if starts with $CFG->dirrot and is file readable
1563 global $template, $template_files, $CFG;
1565 static $loaded;
1567 if (!isset($loaded)) $loaded = array();
1568 if (!isset($template)) $template = array();
1569 if (!isset($template_files)) $template_files = array();
1571 if (!isset($loaded[$context])) {
1572 if (isset($template_files[$context])) {
1573 if (!isset($template[$context])) {
1574 $template[$context] = '';
1577 // load templates from files
1578 foreach ($template_files[$context] as $k => $tpl) {
1579 // TODO: check again if is readable?
1580 $template[$context] .= @file_get_contents($tpl);
1581 //print_object('Loaded: ' . $tpl);
1583 } else {
1584 // do nothing if not file
1587 $loaded[$context] = true;