web.php 110 KB
Newer Older
1
2
<?php
/**
Francois Marier's avatar
Francois Marier committed
3
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
4
5
 * Copyright (C) 2006-2009 Catalyst IT Ltd and others; see:
 *                         http://wiki.mahara.org/Contributors
6
 *
Francois Marier's avatar
Francois Marier committed
7
8
9
10
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
11
 *
Francois Marier's avatar
Francois Marier committed
12
13
14
15
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
16
 *
Francois Marier's avatar
Francois Marier committed
17
18
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20
21
 *
 * @package    mahara
 * @subpackage core
22
 * @author     Catalyst IT Ltd
23
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
24
 * @copyright  (C) 2006-2009 Catalyst IT Ltd http://catalyst.net.nz
25
26
27
28
29
30
 * @copyright  (C) portions from Moodle, (C) Martin Dougiamas http://dougiamas.com
 */

defined('INTERNAL') || die();


31
32
33
function smarty_core() {
    require_once 'dwoo/dwoo/dwooAutoload.php';
    require_once 'dwoo/mahara/Dwoo_Mahara.php';
34

35
    return new Dwoo_Mahara();
36
37
38
}


39
40
41
42
43
44
/**
 * This function creates a Smarty object and sets it up for use within our
 * podclass app, setting up some variables.
 *
 * The variables that it sets up are:
 *
45
 * - WWWROOT: The base url for the Mahara system
46
47
48
49
50
 * - USER: The user object
 * - JAVASCRIPT: A list of javascript files to include in the header.  This
 *   list is passed into this function (see below).
 * - HEADERS: An array of any further headers to set.  Each header is just
 *   straight HTML (see below).
51
52
 * - PUBLIC: Set true if this page is a public page
 * - MAINNAV: Array defining the main navigation
53
 *
54
 * @param $javascript A list of javascript includes.  Each include should be just
55
 *                    the name of a file, and reside in js/{filename}
56
57
58
 * @param $headers    A list of additional headers.  These are to be specified as
 *                    actual HTML.
 * @param $strings    A list of language strings required by the javascript code.
59
60
 * @return Smarty
 */
61

62
function smarty($javascript = array(), $headers = array(), $pagestrings = array(), $extraconfig = array()) {
63
    global $USER, $SESSION, $THEME;
64
65
66
67
68
69
70
71
72
73
74

    if (!is_array($headers)) {
        $headers = array();
    }
    if (!is_array($pagestrings)) {
        $pagestrings = array();
    }
    if (!is_array($extraconfig)) {
        $extraconfig = array();
    }

Martyn Smith's avatar
Martyn Smith committed
75
    $SIDEBLOCKS = array();
76

77
78
    $smarty = smarty_core();

79
    $wwwroot = get_config('wwwroot');
80
    // NOTE: not using jswwwroot - it seems to wreck image paths if you 
81
    // drag them around the wysiwyg editor
82
    $jswwwroot = json_encode($wwwroot);
Martyn Smith's avatar
Martyn Smith committed
83
84

    $theme_list = array();
85
86
87
88
    
    if (function_exists('pieform_get_headdata')) {
        $headers = array_merge($headers, pieform_get_headdata());
    }
89

90
    // Insert the appropriate javascript tags 
91
    $javascript_array = array();
92
    $jsroot = $wwwroot . 'js/';
93

94
95
    $langdirection = get_string('thisdirection', 'langconfig');

Richard Mansfield's avatar
Richard Mansfield committed
96
    // TinyMCE must be included first for some reason we're not sure about
97
    $checkarray = array(&$javascript, &$headers);
98
    $found_tinymce = false;
99
    foreach ($checkarray as &$check) {
100
101
102
103
        if (($key = array_search('tinymce', $check)) !== false || ($key = array_search('tinytinymce', $check)) !== false) {
            if (!$found_tinymce) {
                $found_tinymce = $check[$key];
                $javascript_array[] = $jsroot . 'tinymce/tiny_mce.js';
104
                $content_css = json_encode($THEME->get_url('style/tinymce.css'));
105
                $language = substr(current_language(), 0, 2);
106
107
108
                if ($language != 'en' && !file_exists(get_config('docroot') . 'js/tinymce/langs/' . $language . '.js')) {
                    $language = 'en';
                }
109
                $extrasetup = isset($extraconfig['tinymcesetup']) ? $extraconfig['tinymcesetup'] : '';
110

111
                $adv_buttons = array(
112
                    "undo,redo,separator,bold,italic,underline,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,link,unlink,separator,code,fullscreen",
113
                    "bold,italic,underline,strikethrough,separator,forecolor,backcolor,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,hr,emotions,image,spellchecker,cleanup,separator,link,unlink,separator,code",
114
                    "undo,redo,separator,bullist,numlist,separator,tablecontrols,separator,cut,copy,paste,pasteword",
115
116
117
118
                    "fontselect,separator,fontsizeselect,separator,formatselect",
                );

                // For right-to-left langs, reverse button order & align controls right.
119
120
                $tinymce_langdir = $langdirection == 'rtl' ? 'rtl' : 'ltr';
                $toolbar_align = 'left';
121
122
123

                if ($check[$key] == 'tinymce') {
                    $tinymce_config = <<<EOF
124
    mode: "none",
125
    theme: "advanced",
126
    plugins: "table,emotions,spellchecker,inlinepopups,paste",
127
128
129
    theme_advanced_buttons1 : "{$adv_buttons[1]}",
    theme_advanced_buttons2 : "{$adv_buttons[2]}",
    theme_advanced_buttons3 : "{$adv_buttons[3]}",
130
    theme_advanced_toolbar_location : "top",
131
    theme_advanced_toolbar_align : "{$toolbar_align}",
132
    //width: '512',
133
EOF;
134
135
136
                }
                else {
                    $tinymce_config = <<<EOF
137
    mode: "textareas",
138
139
    editor_selector: 'tinywysiwyg',
    theme: "advanced",
140
    plugins: "fullscreen,inlinepopups,autoresize",
141
    theme_advanced_buttons1 : "{$adv_buttons[0]}",
142
    theme_advanced_buttons2 : "",
143
144
    theme_advanced_buttons3 : "",
    theme_advanced_toolbar_location : "top",
145
    theme_advanced_toolbar_align : "{$toolbar_align}",
146
147
148
149
    fullscreen_new_window: true,
    fullscreen_settings: {
        theme: "advanced",
        plugins: "table,emotions,iespell,inlinepopups,paste",
150
151
152
        theme_advanced_buttons1 : "{$adv_buttons[1]}",
        theme_advanced_buttons2 : "{$adv_buttons[2]}",
        theme_advanced_buttons3 : "{$adv_buttons[3]}"
153
    },
154
EOF;
155
                }
156

157
                $headers[] = <<<EOF
158
159
160
161
<script type="text/javascript">
tinyMCE.init({
    button_tile_map: true,
    {$tinymce_config}
162
    extended_valid_elements : "object[width|height|classid|codebase],param[name|value],embed[src|type|width|height|flashvars|wmode],script[src,type,language],+ul[id|type|compact],iframe[src|width|height|align|title|class|type|frameborder|allowfullscreen]",
163
    urlconverter_callback : "custom_urlconvert",
164
    language: '{$language}',
165
    directionality: "{$tinymce_langdir}",
166
    content_css : {$content_css},
167
    //document_base_url: {$jswwwroot},
168
    remove_script_host: false,
169
170
171
    relative_urls: false,
    setup: function(ed) {
        ed.onInit.add(function(ed) {
172
            if (typeof(editor_to_focus) == 'string' && ed.editorId == editor_to_focus) {
173
174
175
                ed.focus();
            }
        });
176
        {$extrasetup}
177
    }
178
});
179
function custom_urlconvert (u, n, e) {
180
  // Don't convert the url on the skype status buttons.
181
182
  if (u.indexOf('skype:') == 0) {
      return u;
183
  }
184
185
186
187
188
189
190
191
192
193
194
195
196
197
  var t = tinyMCE.activeEditor, s = t.settings;

  // Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs
  if (!s.convert_urls || (e && e.nodeName == 'LINK') || u.indexOf('file:') === 0)
      return u;

  // Convert to relative
  if (s.relative_urls)
      return t.documentBaseURI.toRelative(u);

  // Convert to absolute
  u = t.documentBaseURI.toAbsolute(u, s.remove_script_host);

  return u;
198
}
199
200
201
</script>

EOF;
202
203
204
205
206
207
208
                unset($check[$key]);
            }
            else {
                if ($check[$key] != $found_tinymce) {
                    log_warn('Two differently configured tinyMCE instances have been asked for on this page! This is not possible');
                }
                unset($check[$key]);
209
            }
210
        }
211
212
        // Load jquery first, so that it doesn't break Mochikit
        if (($key = array_search('jquery', $check)) !== false) {
213
            $jquery = (get_config('developermode') & DEVMODE_UNPACKEDJS) ? 'jquery-1.5.2.js' : 'jquery-1.5.2.min.js';
214
215
216
217
218
            array_unshift($javascript_array, $jsroot . 'jquery/' . $jquery);
            // Make jQuery accessible with $j (Mochikit has $)
            $headers[] = '<script type="text/javascript">$j=jQuery;</script>';
            unset($check[$key]);
        }
219
    }
220

221
    if (get_config('developermode') & DEVMODE_UNPACKEDJS) {
222
        $javascript_array[] = $jsroot . 'MochiKit/MochiKit.js';
223
224
225
226
        $javascript_array[] = $jsroot . 'MochiKit/Position.js';
        $javascript_array[] = $jsroot . 'MochiKit/Color.js';
        $javascript_array[] = $jsroot . 'MochiKit/Visual.js';
        $javascript_array[] = $jsroot . 'MochiKit/DragAndDrop.js';
227
        $javascript_array[] = $jsroot . 'MochiKit/Format.js';
228
229
230
231
    }
    else {
        $javascript_array[] = $jsroot . 'MochiKit/Packed.js';
    }
Martyn Smith's avatar
Martyn Smith committed
232
    $javascript_array[] = $jsroot . 'keyboardNavigation.js';
233

234
    $strings = array();
235
236
237
238
239
240
241
242
243
    foreach ($pagestrings as $k => $v) {
        if (is_array($v)) {
            foreach ($v as $tag) {
                $strings[$tag] = get_raw_string($tag, $k);
            }
        }
        else {
            $strings[$k] = get_raw_string($k, $v);
        }
244
245
    }

246
    $jsstrings = jsstrings();
Martyn Smith's avatar
Martyn Smith committed
247
    $themepaths = themepaths();
248

Richard Mansfield's avatar
Richard Mansfield committed
249
    foreach ($javascript as $jsfile) {
250
251
252
253
        // For now, if there's no path in the js file, assume it's in
        // $jsroot and append '.js' to the name.  Later we may want to
        // ensure all smarty() calls include the full path to the js
        // file, with the proper extension.
254
        if (strpos($jsfile, '/') === false) {
255
            $javascript_array[] = $jsroot . $jsfile . '.js';
256
            if (isset($jsstrings[$jsfile])) {
257
258
259
                foreach ($jsstrings[$jsfile] as $section => $tags) {
                    foreach ($tags as $tag) {
                        $strings[$tag] = get_raw_string($tag, $section);
260
261
262
                    }
                }
            }
Martyn Smith's avatar
Martyn Smith committed
263
264
            if (isset($themepaths[$jsfile])) {
                foreach ($themepaths[$jsfile] as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
265
                    $theme_list[$themepath] = $THEME->get_url($themepath);
Martyn Smith's avatar
Martyn Smith committed
266
267
                }
            }
268
        }
269
270
        else if (strpos($jsfile, 'http://') === false) {
            // A local .js file with a fully specified path
271
            $javascript_array[] = $wwwroot . $jsfile;
272
273
274
275
276
277
            // If $jsfile is from a plugin (i.e. plugintype/pluginname/js/foo.js)
            // Then get js strings from static function jsstrings in plugintype/pluginname/lib.php 
            $bits = explode('/', $jsfile);
            if (count($bits) == 4) {
                safe_require($bits[0], $bits[1]);
                $pluginclass = generate_class_name($bits[0], $bits[1]);
278
                $name = substr($bits[3], 0, strpos($bits[3], '.js'));
279
280
                if (is_callable(array($pluginclass, 'jsstrings'))) {
                    $tempstrings = call_static_method($pluginclass, 'jsstrings', $name);
281
282
283
                    foreach ($tempstrings as $section => $tags) {
                        foreach ($tags as $tag) {
                            $strings[$tag] = get_raw_string($tag, $section);
284
285
                        }
                    }
Richard Mansfield's avatar
Richard Mansfield committed
286
                }
287
288
289
290
291
292
293
294
295
                if (is_callable(array($pluginclass, 'jshelp'))) {
                    $tempstrings = call_static_method($pluginclass, 'jshelp', $name);
                    foreach ($tempstrings as $section => $tags) {
                        foreach ($tags as $tag) {
                            $strings[$tag . '.help'] = get_help_icon($bits[0], $bits[1], null, null,
                                                                     null, $tag);
                        }
                    }
                }
Martyn Smith's avatar
Martyn Smith committed
296
297
298
                if (is_callable(array($pluginclass, 'themepaths'))) {
                    $tmpthemepaths = call_static_method($pluginclass, 'themepaths', $name);
                    foreach ($tmpthemepaths as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
299
                        $theme_list[$themepath] = $THEME->get_url($themepath);
Martyn Smith's avatar
Martyn Smith committed
300
301
                    }
                }
Martyn Smith's avatar
Martyn Smith committed
302
            }
Martyn Smith's avatar
Martyn Smith committed
303
        }
304
305
306
307
        else {
            // A remote .js file
            $javascript_array[] = $jsfile;
        }
308
    }
309
310

    $javascript_array[] = $jsroot . 'mahara.js';
311
    if (get_config('developermode') & DEVMODE_DEBUGJS) {
312
        $javascript_array[] = $jsroot . 'debug.js';
313
    }
314

315
316
317
    foreach ($jsstrings['mahara'] as $section => $tags) {
        foreach ($tags as $tag) {
            $strings[$tag] = get_raw_string($tag, $section);
318
319
        }
    }
320
321
    if (isset($extraconfig['themepaths']) && is_array($extraconfig['themepaths'])) {
        foreach ($extraconfig['themepaths'] as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
322
            $theme_list[$themepath] = $THEME->get_url($themepath);
323
324
        }
    }
325

326
    $stringjs = '<script type="text/javascript">';
327
    $stringjs .= 'var strings = ' . json_encode($strings) . ';';
328
329
    $stringjs .= '</script>';

330
    // stylesheet set up - if we're in a plugin also get its stylesheet
Nigel McNie's avatar
Nigel McNie committed
331
    $stylesheets = array_reverse(array_values($THEME->get_url('style/style.css', true)));
332
    if (defined('SECTION_PLUGINTYPE') && defined('SECTION_PLUGINNAME') && SECTION_PLUGINTYPE != 'core') {
Nigel McNie's avatar
Nigel McNie committed
333
        if ($pluginsheets = $THEME->get_url('style/style.css', true, SECTION_PLUGINTYPE . '/' . SECTION_PLUGINNAME)) {
334
335
336
            $stylesheets = array_merge($stylesheets, array_reverse($pluginsheets));
        }
    }
337
    if (defined('ADMIN') || defined('INSTITUTIONALADMIN')) {
338
339
340
        if ($adminsheets = $THEME->get_url('style/admin.css', true)) {
            $stylesheets = array_merge($stylesheets, array_reverse($adminsheets));
        }
341
    }
342
    if (get_config('developermode') & DEVMODE_DEBUGCSS) {
343
344
        $stylesheets[] = get_config('wwwroot') . 'theme/debug.css';
    }
345

346
347
348
    // look for extra stylesheets
    if (isset($extraconfig['stylesheets']) && is_array($extraconfig['stylesheets'])) {
        foreach ($extraconfig['stylesheets'] as $extrasheet) {
349
            if ($sheets = $THEME->get_url($extrasheet, true)) {
Nigel McNie's avatar
Nigel McNie committed
350
                $stylesheets = array_merge($stylesheets, array_reverse(array_values($sheets)));
351
352
353
            }
        }
    }
354
355
356
    if ($sheets = $THEME->additional_stylesheets()) {
        $stylesheets = array_merge($stylesheets, $sheets);
    }
357

358
    // Include rtl.css for right-to-left langs
359
    if ($langdirection == 'rtl') {
360
        $smarty->assign('LANGDIRECTION', 'rtl');
361
362
363
364
365
        if ($rtlsheets = $THEME->get_url('style/rtl.css', true)) {
            $stylesheets = array_merge($stylesheets, array_reverse($rtlsheets));
        }
    }

366
    $smarty->assign('STRINGJS', $stringjs);
367

368
    $smarty->assign('STYLESHEETLIST', $stylesheets);
369
370
371
372
    if (!empty($theme_list)) {
        // this gets assigned in smarty_core, but do it again here if it's changed locally
        $smarty->assign('THEMELIST', json_encode(array_merge((array)json_decode($smarty->get_template_vars('THEMELIST')),  $theme_list))); 
    }
373

374
375
376
377
    $dropdownmenu = get_config('dropdownmenu');
    if ($dropdownmenu) {
        $smarty->assign('DROPDOWNMENU', $dropdownmenu);
    }
378

379
380
381
382
    $sitename = get_config('sitename');
    if (!$sitename) {
       $sitename = 'Mahara';
    }
383
    $smarty->assign('sitename', $sitename);
384
    $smarty->assign('sitelogo', $THEME->header_logo());
385

Martyn Smith's avatar
Martyn Smith committed
386
    if (defined('TITLE')) {
387
        $smarty->assign('PAGETITLE', TITLE . ' - ' . $sitename);
388
        $smarty->assign('heading', TITLE);
Martyn Smith's avatar
Martyn Smith committed
389
390
    }
    else {
391
        $smarty->assign('PAGETITLE', $sitename);
Martyn Smith's avatar
Martyn Smith committed
392
393
    }

394
395
396
    if (function_exists('local_header_top_content')) {
        $smarty->assign('SITETOP', local_header_top_content());
    }
397
398
399
    if (defined('PUBLIC')) {
        $smarty->assign('PUBLIC', true);
    }
400
401
402
    if (defined('ADMIN')) {
        $smarty->assign('ADMIN', true);
    }
403
404
405
    if (defined('INSTITUTIONALADMIN')) {
        $smarty->assign('INSTITUTIONALADMIN', true);
    }
406

407
408
    $smarty->assign('LOGGEDIN', $USER->is_logged_in());
    if ($USER->is_logged_in()) {
409
        global $SELECTEDSUBNAV; // It's evil, but rightnav & mainnav stuff are now in different templates.
410
        $smarty->assign('MAINNAV', main_nav());
411
        $smarty->assign('RIGHTNAV', right_nav());
412
        $smarty->assign('SELECTEDSUBNAV', $SELECTEDSUBNAV);
413
    }
414
    else {
415
        $smarty->assign('languageform', language_select_form());
416
    }
417
    $smarty->assign('FOOTERMENU', footer_menu());
418

419
    $smarty->assign_by_ref('USER', $USER);
420
    $smarty->assign('SESSKEY', $USER->get('sesskey'));
421
    $smarty->assign_by_ref('JAVASCRIPT', $javascript_array);
422
    $smarty->assign_by_ref('HEADERS', $headers);
423
424
    $siteclosedforupgrade = get_config('siteclosed');
    if ($siteclosedforupgrade && get_config('disablelogin')) {
425
        $smarty->assign('SITECLOSED', 'logindisabled');
426
427
    }
    else if ($siteclosedforupgrade || get_config('siteclosedbyadmin')) {
428
        $smarty->assign('SITECLOSED', 'loginallowed');
429
    }
430

431
432
    if ((!isset($extraconfig['pagehelp']) || $extraconfig['pagehelp'] !== false)
        and $help = has_page_help()) {
433
434
435
        $smarty->assign('PAGEHELPNAME', $help[0]);
        $smarty->assign('PAGEHELPICON', $help[1]);
    }
436
    if (defined('GROUP')) {
437
        require_once('group.php');
438
439
        $group = group_current_group();
        $smarty->assign('GROUP', $group);
440
441
442
443
        if (!defined('NOGROUPMENU')) {
            $smarty->assign('SUBPAGENAV', group_get_menu_tabs());
            $smarty->assign('PAGEHEADING', $group->name);
        }
444
    }
445

Martyn Smith's avatar
Martyn Smith committed
446
    // ---------- sideblock stuff ----------
447
448
    $sidebars = !isset($extraconfig['sidebars']) || $extraconfig['sidebars'] !== false;
    if ($sidebars && !defined('INSTALLER') && (!defined('MENUITEM') || substr(MENUITEM, 0, 5) != 'admin')) {
Richard Mansfield's avatar
Richard Mansfield committed
449
        if (get_config('installed') && !defined('ADMIN') && !defined('INSTITUTIONALADMIN')) {
450
451
452
453
            $data = site_menu();
            if (!empty($data)) {
                $smarty->assign('SITEMENU', site_menu());
                $SIDEBLOCKS[] = array(
454
                    'name'   => 'linksandresources',
455
456
457
458
459
460
                    'weight' => 10,
                    'data'   => $data,
                );
            }
        }

461
462
        if ($USER->is_logged_in() && defined('MENUITEM') &&
            (substr(MENUITEM, 0, 11) == 'myportfolio' || substr(MENUITEM, 0, 7) == 'content')) {
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
            if (get_config('showselfsearchsideblock')) {
                $SIDEBLOCKS[] = array(
                    'name'   => 'selfsearch',
                    'weight' => 0,
                    'data'   => array(),
                );
            }
            if (get_config('showtagssideblock')) {
                $SIDEBLOCKS[] = array(
                    'name'   => 'tags',
                    'id'     => 'sb-tags',
                    'weight' => 0,
                    'data'   => tags_sideblock(),
                );
            }
Clare Lenihan's avatar
Clare Lenihan committed
478
        }
Clare Lenihan's avatar
Clare Lenihan committed
479

Richard Mansfield's avatar
Richard Mansfield committed
480
        if($USER->is_logged_in() && !defined('ADMIN') && !defined('INSTITUTIONALADMIN')) {
481
482
            $SIDEBLOCKS[] = array(
                'name'   => 'profile',
483
                'id'     => 'sb-profile',
484
485
486
                'weight' => -20,
                'data'   => profile_sideblock()
            );
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
            $showusers = 2;
            $institutions = $USER->institutions;
            if (!empty($institutions)) {
                $showusers = 0;
                foreach ($institutions as $i) {
                    if ($i->showonlineusers == 2) {
                        $showusers = 2;
                        break;
                    }
                    if ($i->showonlineusers == 1) {
                        $showusers = 1;
                    }
                }
            }
            if (get_config('showonlineuserssideblock') && $showusers > 0) {
502
503
                $SIDEBLOCKS[] = array(
                    'name'   => 'onlineusers',
504
                    'id'     => 'sb-onlineusers',
505
506
507
508
                    'weight' => -10,
                    'data'   => onlineusers_sideblock(),
                );
            }
509
        }
Martyn Smith's avatar
Martyn Smith committed
510

Richard Mansfield's avatar
Richard Mansfield committed
511
512
513
        if(defined('GROUP')) {
            $SIDEBLOCKS[] = array(
                'name'   => 'group',
514
                'id'     => 'sb-groupnav',
Richard Mansfield's avatar
Richard Mansfield committed
515
516
517
518
519
                'weight' => -10,
                'data'   => group_sideblock()
            );
        }

520
        if (!$USER->is_logged_in() && !(get_config('siteclosed') && get_config('disablelogin'))) {
521
            $SIDEBLOCKS[] = array(
522
523
                'name'   => 'login',
                'weight' => -10,
524
                'id'     => 'sb-loginbox',
525
526
527
                'data'   => array(
                    'loginform' => auth_generate_login_form(),
                ),
528
529
            );
        }
530

531
532
533
534
535
536
537
538
539
        if (get_config('enablenetworking')) {
            require_once(get_config('docroot') .'api/xmlrpc/lib.php');
            if ($USER->is_logged_in() && $ssopeers = get_service_providers($USER->authinstance)) {
                $SIDEBLOCKS[] = array(
                    'name'   => 'ssopeers',
                    'weight' => 1,
                    'data'   => $ssopeers,
                );
            }
Martyn Smith's avatar
Martyn Smith committed
540
541
        }

542
543
544
545
546
        if (isset($extraconfig['sideblocks']) && is_array($extraconfig['sideblocks'])) {
            foreach ($extraconfig['sideblocks'] as $sideblock) {
                $SIDEBLOCKS[] = $sideblock;
            }
        }
Martyn Smith's avatar
Martyn Smith committed
547

548
549
        usort($SIDEBLOCKS, create_function('$a,$b', 'if ($a["weight"] == $b["weight"]) return 0; return ($a["weight"] < $b["weight"]) ? -1 : 1;'));

550
551
552
        // Place all sideblocks on the right. If this structure is munged 
        // appropriately, you can put blocks on the left. In future versions of 
        // Mahara, we'll make it easy to do this.
553
        $sidebars = $sidebars && !empty($SIDEBLOCKS);
554
        $SIDEBLOCKS = array('left' => array(), 'right' => $SIDEBLOCKS);
555

556
        $smarty->assign('userauthinstance', $SESSION->get('authinstance'));
557
        $smarty->assign('MNETUSER', $SESSION->get('mnetuser'));
558
        $smarty->assign('SIDEBLOCKS', $SIDEBLOCKS);
559
        $smarty->assign('SIDEBARS', $sidebars);
560

561
562
563
564
    }

    if ($USER->get('parentuser')) {
        $smarty->assign('USERMASQUERADING', true);
565
        $smarty->assign('masqueradedetails', get_string('youaremasqueradingas', 'mahara', display_name($USER)));
566
567
        $smarty->assign('becomeyouagain',
            ' <a href="' . hsc($wwwroot) . 'admin/users/changeuser.php?restore=1">'
568
            . get_string('becomeadminagain', 'admin', hsc($USER->get('parentuser')->name))
569
            . '</a>');
570
    }
Martyn Smith's avatar
Martyn Smith committed
571

572
573
574
    return $smarty;
}

575
576
577
578
579
580
581
582
583
584
585
586
587
588

/**
 * Manages theme configuration.
 *
 * Does its best to give the user _a_ theme, even if it's not the theme they 
 * want to use (e.g. the theme they want has been uninstalled)
 */
class Theme {

    /**
     * The base name of the theme (the name of the directory in which it lives)
     */
    public $basename = '';

589
590
591
592
593
    /**
     * A user may have had the header logo overridden by an institution
     */
    public $headerlogo;

594
595
596
597
598
    /**
     * Additional stylesheets to display after the basename theme's stylesheets
     */
    public $addedstylesheets;

599
600
601
602
603
604
605
606
607
608
    /**
     * A human-readable version of the theme name
     */
    public $displayname = '';

    /**
     * Which pieform renderer to use by default for all forms
     */
    public $formrenderer = '';

609
610
611
612
613
614
615
616
617
618
    /**
     * Directories where to look for templates by default
     */
    public $templatedirs = array();

    /**
     * Theme inheritance path from this theme to 'raw'
     */
    public $inheritance = array();

619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
    /**
     * What unit the left/center/right column widths are in. 'pixels' or 'percent'
     */
    public $columnwidthunits    = '';

    /**
     * Width of the left column. Integer - see $columnwidthunits
     */
    public $leftcolumnwidth     = 256;

    /**
     * Background colour for the left column
     */
    public $leftcolumnbgcolor   = '#fff';

    /**
     * Background colour for the center column
     */
    public $centercolumnbgcolor = '#fff';

    /**
     * Width of the right column. Integer - see $columnwidthunits
     */
    public $rightcolumnwidth    = 256;

    /**
     * Background colour for the right column
     */
    public $rightcolumnbgcolor  = '#fff';


    /**
     * Initialises a theme object based on the theme 'hint' passed.
     *
     * If arg is a string, it's taken to be a theme name. If it's a user 
     * object, we ask it for a theme name. If it's an integer, we pretend 
     * that's a user ID and ask for the theme for that user.
     *
     * If the theme they want doesn't exist, the object is initialised for the 
     * default theme. This means you can initialise one of these for a user
     * and then use it without worrying if the theme exists.
     *
     * @param mixed $arg Theme name, user object or user ID
     */
    public function __construct($arg) {
        if (is_string($arg)) {
            $themename = $arg;
666
            $themedata = null;
667
668
        }
        else if ($arg instanceof User) {
669
            $themedata = $arg->get_themedata();
670
671
672
673
        }
        else if (is_int($arg)) {
            $user = new User();
            $user->find_by_id($arg);
674
            $themedata = $user->get_themedata();
675
676
677
678
679
        }
        else {
            throw new SystemException("Argument to Theme::__construct was not a theme name, user object or user ID");
        }

680
681
682
683
        if (isset($themedata)) {
            $themename = $themedata->basename;
        }

684
685
        if (!$themename) {
            // Theme to show to when no theme has been suggested
686
687
688
            if (!$themename = get_config('theme')) {
                $themename = 'raw';
            }
689
        }
690
691

        // check the validity of the name
692
        if (!$this->name_is_valid($themename)) {
693
694
            throw new SystemException("Theme name is in invalid form: '$themename'");
        }
695
696

        $this->init_theme($themename, $themedata);
697
698
699
700
701
702
703
704
    }

    /**
     * Given a theme name, check that it is valid
     */
    public static function name_is_valid($themename) {
        // preg_match returns 0 if invalid characters were found, 1 if not
        return (preg_match('/^[a-zA-Z0-9_-]+$/', $themename) == 1);
705
706
707
708
709
    }

    /**
     * Given a theme name, reads in all config and sets fields on this object
     */
710
    private function init_theme($themename, $themedata) {
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
        $this->basename = $themename;

        $themeconfigfile = get_config('docroot') . 'theme/' . $this->basename . '/themeconfig.php';
        if (!is_readable($themeconfigfile)) {
            // We can safely assume that the default theme is installed, users 
            // should never be able to remove it
            $this->basename = 'default';
            $themeconfigfile = get_config('docroot') . 'theme/default/themeconfig.php';
        }

        require($themeconfigfile);

        foreach (get_object_vars($theme) as $key => $value) {
            $this->$key = $value;
        }

        if (!isset($this->displayname)) {
728
            $this->displayname = $this->basename;
729
730
731
732
733
        }
        if (!isset($theme->parent) || !$theme->parent) {
            $theme->parent = 'raw';
        }

734
735
736
        $this->templatedirs[] = get_config('docroot') . 'theme/' . $this->basename . '/templates/';
        $this->inheritance[]  = $this->basename;

737
738
739
740
741
742
743
744
        // Now go through the theme hierarchy assigning variables from the 
        // parent themes
        $currenttheme = $this->basename;
        while ($currenttheme != 'raw') {
            $currenttheme = isset($theme->parent) ? $theme->parent : 'raw';
            $parentconfigfile = get_config('docroot') . 'theme/' . $currenttheme . '/themeconfig.php';
            require($parentconfigfile);
            foreach (get_object_vars($theme) as $key => $value) {
745
                if (!isset($this->$key) || !$this->$key) {
746
747
748
                    $this->$key = $value;
                }
            }
749
750
            $this->templatedirs[] = get_config('docroot') . 'theme/' . $currenttheme . '/templates/';
            $this->inheritance[]  = $currenttheme;
751
        }
752
753
754
755

        if (!empty($themedata->headerlogo)) {
            $this->headerlogo = $themedata->headerlogo;
        }
756
757
758
        if (!empty($themedata->stylesheets)) {
            $this->addedstylesheets = $themedata->stylesheets;
        }
759
760
    }

761
762
763
    /**
     * stuff
     */
764
765
    public function get_url($filename, $all=false, $plugindirectory='') {
        return $this->_get_path($filename, $all, $plugindirectory, get_config('wwwroot'));
766
767
    }

768
769
    public function get_path($filename, $all=false, $plugindirectory='') {
        return $this->_get_path($filename, $all, $plugindirectory, get_config('docroot'));
770
771
    }

772
    private function _get_path($filename, $all, $plugindirectory, $returnprefix) {
773
        $list = array();
774
        $plugindirectory = ($plugindirectory && substr($plugindirectory, -1) != '/') ? $plugindirectory . '/' : $plugindirectory;
775
776

        foreach ($this->inheritance as $themedir) {
777
            if (is_readable(get_config('docroot') . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename)) {
778
                if ($all) {
779
                    $list[$themedir] = $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
780
781
                }
                else {
782
                    return $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
783
784
785
786
787
788
789
790
                }
            }
        }
        if ($all) {
            return $list;
        }

        $extra = '';
791
792
        if ($plugindirectory) {
            $extra = ", plugindir $plugindirectory";
793
794
        }
        log_debug("Missing file in theme {$this->basename}{$extra}: $filename");
795
        return $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
796
797
    }

798
799
800
801
802
803
    public function header_logo() {
        if (!empty($this->headerlogo)) {
            return get_config('wwwroot') . 'thumb.php?type=logobyid&id=' . $this->headerlogo;
        }
        return $this->get_url('images/site-logo.png');
    }
804
805
806
807

    public function additional_stylesheets() {
        return $this->addedstylesheets;
    }
808
809
810
}


811
812
/** 
 * Returns the lists of strings used in the .js files
813
 * @return array                   
814
815
 */

816
function jsstrings() {
Martyn Smith's avatar
Martyn Smith committed
817
    return array(
818
819
820
       'mahara' => array(                        // js file
            'mahara' => array(                   // section
                'namedfieldempty',               // string name
821
                'processing',
822
823
824
                'requiredfieldempty',
                'unknownerror',
                'loading',
Martyn Smith's avatar
Martyn Smith committed
825
                'showtags',
826
827
                'unreadmessages',
                'unreadmessage',
828
829
                'pendingfriend',
                'pendingfriends',
830
                'couldnotgethelp',
831
832
833
834
835
836
                'password',
                'username',
                'login',
                'sessiontimedout',
                'loginfailed',
                'home',
837
                'youhavenottaggedanythingyet',
838
            ),
839
840
        ),
        'tablerenderer' => array(
841
842
843
844
845
846
            'mahara' => array(
                'firstpage',
                'nextpage',
                'prevpage',
                'lastpage',
            )
847
        ),
848
        'friends' => array(
849
            'group' => array(
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
                'confirmremovefriend',
                'seeallviews',
                'noviewstosee',
                'sendmessage',
                'whymakemeyourfriend',
                'approverequest',
                'denyrequest',
                'pending',
                'removefromfriendslist',
                'views',
                'trysearchingforfriends',
                'nobodyawaitsfriendapproval',
                'sendfriendrequest',
                'addtomyfriends',
                'friendshiprequested',
                'userdoesntwantfriends',
                'existingfriend',
                'nosearchresultsfound',
868
                'reason',
869
                'requestfriendship',
870
                'cancel',
871
872
            ),
        ),
873
874
875
        'views' => array(
            'view' => array(
                'confirmdeleteblockinstance',
876
                'blocksinstructionajax',
877
                'Configure',
878
879
            ),
        ),
880
881
882
883
884
885
886
887
888
        'adminusersearch' => array(
            'admin' => array(
                'suspenduser',
                'suspensionreason',
            ),
            'mahara' => array(
                'cancel',
            ),
        ),
Martyn Smith's avatar
Martyn Smith committed
889
890
891
    );
}

Martyn Smith's avatar
Martyn Smith committed
892
function themepaths() {
893
894
895
896
897
898

    static $paths;
    if (empty($paths)) {
        $paths = array(
            'mahara' => array(
                'images/icon_close.gif',
899
                'images/edit.gif',
900
901
902
                'images/failure.gif',
                'images/loading.gif',
                'images/success.gif',
903
                'images/icon_problem.gif',
904
                'images/icon_help.gif',
905
                'style/js.css',
906
907
908
909
            ),
        );
    }
    return $paths;
Martyn Smith's avatar
Martyn Smith committed
910
911
}

912
913
914
915
916
917
/** 
 * Takes an array of string identifiers and returns an array of the
 * corresponding strings, quoted for use in inline javascript here
 * docs.
 */

918
919
920
921
function quotestrings($strings) {
    $qstrings = array();
    foreach ($strings as $section => $tags) {
        foreach ($tags as $tag) {
922
            $qstrings[$tag] = json_encode(get_string($tag, $section));
923
        }
924
    }
925
    return $qstrings;
926
927
}

928
929
930
931
932
933
934
/** 
 * This function sets up and caches info about the current selected theme
 * contains inheritance path (used for locating images) and template dirs
 * and potentially more stuff later ( like mime header to send (html vs xhtml))
 * @return object
 */
function theme_setup() {
935
936
937
    global $THEME;
    log_warn("theme_setup() is deprecated - please use the global \$THEME object instead");
    return $THEME;
938
939
940
941
942
943
944
945
}

/** 
 * This function returns the full url to an image
 * Always use it to get image urls
 * @param $imagelocation path to image relative to theme/$theme/static/
 * @param $pluginlocation path to plugin relative to docroot
 */
946
function theme_get_url($location, $pluginlocation='', $all = false) {
947
948
949
950
951
952
    global $THEME;
    log_warn("theme_get_url() is deprecated: Use \$THEME->get_url() instead");
    $plugintype = $pluginname = '';
    if ($pluginlocation) {
        list($plugintype, $pluginname) = explode('/', $pluginlocation);
        $pluginname = substr($pluginname, 0, -1);
953
    }
954
    return $THEME->get_url($location, $all, $plugintype, $pluginname);