web.php 93.7 KB
Newer Older
1
2
<?php
/**
Francois Marier's avatar
Francois Marier committed
3
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
4
 * Copyright (C) 2006-2008 Catalyst IT Ltd (http://www.catalyst.net.nz)
5
 *
Francois Marier's avatar
Francois Marier committed
6
7
8
9
 * 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.
10
 *
Francois Marier's avatar
Francois Marier committed
11
12
13
14
 * 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.
15
 *
Francois Marier's avatar
Francois Marier committed
16
17
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19
20
 *
 * @package    mahara
 * @subpackage core
21
 * @author     Catalyst IT Ltd
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
23
 * @copyright  (C) 2006-2008 Catalyst IT Ltd http://catalyst.net.nz
24
25
26
27
28
29
 * @copyright  (C) portions from Moodle, (C) Martin Dougiamas http://dougiamas.com
 */

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


30
function &smarty_core() {
31
    global $THEME;
32
    require_once('smarty/libs/Smarty.class.php');
33
34
35
36
    $smarty =& new Smarty();
    
    $themepaths = themepaths();

37
    $smarty->template_dir = $THEME->templatedirs;
38

39
40
41
42
    check_dir_exists(get_config('dataroot') . 'smarty/compile/' . $THEME->basename);
    check_dir_exists(get_config('dataroot') . 'smarty/cache/' . $THEME->basename);
    $smarty->compile_dir   = get_config('dataroot') . 'smarty/compile/' . $THEME->basename;
    $smarty->cache_dir     = get_config('dataroot') . 'smarty/cache/' . $THEME->basename;
43
    $smarty->plugins_dir[] = get_config('libroot') . 'smarty/mahara/';
44

45
    $smarty->assign('THEME', $THEME);
46
47
48
49
    $smarty->assign('WWWROOT', get_config('wwwroot'));

    $theme_list = array();
    foreach ($themepaths['mahara'] as $themepath) {
50
        $theme_list[$themepath] = $THEME->get_url($themepath);
51
52
53
54
55
56
57
    }
    $smarty->assign('THEMELIST', json_encode($theme_list));

    return $smarty;
}


58
59
60
61
62
63
/**
 * 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:
 *
64
 * - WWWROOT: The base url for the Mahara system
65
66
67
68
69
 * - 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).
70
71
 * - PUBLIC: Set true if this page is a public page
 * - MAINNAV: Array defining the main navigation
72
 *
73
 * @param $javascript A list of javascript includes.  Each include should be just
74
 *                    the name of a file, and reside in js/{filename}
75
76
77
 * @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.
78
79
 * @return Smarty
 */
80

81
function &smarty($javascript = array(), $headers = array(), $pagestrings = array(), $extraconfig = array()) {
82
    global $USER, $SESSION, $THEME;
83
84
85
86
87
88
89
90
91
92
93

    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
94
    $SIDEBLOCKS = array();
95

96
    $smarty = smarty_core();
97
    $smarty->register_function('user_search_form', 'user_search_form');
98

99
    $wwwroot = get_config('wwwroot');
100
    // NOTE: not using jswwwroot - it seems to wreck image paths if you 
101
    // drag them around the wysiwyg editor
102
    $jswwwroot = json_encode($wwwroot);
Martyn Smith's avatar
Martyn Smith committed
103
104

    $theme_list = array();
105
106
107
108
    
    if (function_exists('pieform_get_headdata')) {
        $headers = array_merge($headers, pieform_get_headdata());
    }
109

110
    // Insert the appropriate javascript tags 
111
    $javascript_array = array();
112
    $jsroot = $wwwroot . 'js/';
113

Richard Mansfield's avatar
Richard Mansfield committed
114
    // TinyMCE must be included first for some reason we're not sure about
115
    $checkarray = array(&$javascript, &$headers);
116
    $found_tinymce = false;
117
    foreach ($checkarray as &$check) {
118
119
120
121
        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';
122
                $content_css = json_encode($THEME->get_url('style/tinymce.css'));
123
124
                $language = substr(current_language(), 0, 2);
                $execcommand = '';
125
126
                if (isset($extraconfig['tinymcesetup'])) {
                    $execcommand = 'setup: ' . $extraconfig['tinymcesetup'] . ',';
127
                }
128

129
130
                    if ($check[$key] == 'tinymce') {
                        $tinymce_config = <<<EOF
131
    mode: "none",
132
    theme: "advanced",
133
    plugins: "table,emotions,iespell,inlinepopups,paste",
134
    theme_advanced_buttons1 : "bold,italic,underline,strikethrough,separator,forecolor,backcolor,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,hr,emotions,image,iespell,cleanup,separator,link,unlink,separator,code",
135
    theme_advanced_buttons2 : "bullist,numlist,separator,tablecontrols,separator,cut,copy,paste,pasteword",
136
    theme_advanced_buttons3 : "fontselect,separator,fontsizeselect,separator,formatselect",
137
    theme_advanced_toolbar_location : "top",
138
139
    theme_advanced_toolbar_align : "left",
    //width: '512',
140
EOF;
141
142
143
                    }
                    else {
                        $tinymce_config = <<<EOF
144
    mode: "textareas",
145
146
    editor_selector: 'tinywysiwyg',
    theme: "advanced",
147
    plugins: "fullscreen,inlinepopups",
148
149
    theme_advanced_buttons1 : "bold,italic,underline,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,bullist,numlist,separator,link,unlink,separator,code,fullscreen",
    theme_advanced_buttons2 : "",
150
151
    theme_advanced_buttons3 : "",
    theme_advanced_toolbar_location : "top",
152
    theme_advanced_toolbar_align : "left",
153
154
155
156
    fullscreen_new_window: true,
    fullscreen_settings: {
        theme: "advanced",
        plugins: "table,emotions,iespell,inlinepopups,paste",
157
        theme_advanced_buttons1 : "bold,italic,underline,strikethrough,separator,forecolor,backcolor,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,hr,emotions,image,iespell,cleanup,separator,link,unlink,separator,code",
158
159
160
        theme_advanced_buttons2 : "bullist,numlist,separator,tablecontrols,separator,cut,copy,paste,pasteword",
        theme_advanced_buttons3 : "fontselect,separator,fontsizeselect,separator,formatselect"
    },
161
EOF;
162
                }
163

164
                $headers[] = <<<EOF
165
166
167
168
<script type="text/javascript">
tinyMCE.init({
    button_tile_map: true,
    {$tinymce_config}
169
    {$execcommand}
170
    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]",
171
    urlconverter_callback : "custom_urlconvert",
172
    language: '{$language}',
173
    content_css : {$content_css},
174
175
    forced_root_block : "",
    force_p_newlines : false,
176
    apply_source_formatting: false,
177
    //document_base_url: {$jswwwroot},
178
    relative_urls: false
179
});
180
function custom_urlconvert (u, n, e) {
181
  // Don't convert the url on the skype status buttons.
182
183
  if (u.indexOf('skype:') == 0) {
      return u;
184
  }
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  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;
199
}
200
201
202
</script>

EOF;
203
204
205
206
207
208
209
                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]);
210
            }
211
        }
212
213
    }

214
    if (get_config('developermode') & DEVMODE_UNPACKEDJS) {
215
        $javascript_array[] = $jsroot . 'MochiKit/MochiKit.js';
216
217
218
219
        $javascript_array[] = $jsroot . 'MochiKit/Position.js';
        $javascript_array[] = $jsroot . 'MochiKit/Color.js';
        $javascript_array[] = $jsroot . 'MochiKit/Visual.js';
        $javascript_array[] = $jsroot . 'MochiKit/DragAndDrop.js';
220
        $javascript_array[] = $jsroot . 'MochiKit/Format.js';
221
222
223
224
    }
    else {
        $javascript_array[] = $jsroot . 'MochiKit/Packed.js';
    }
Martyn Smith's avatar
Martyn Smith committed
225
    $javascript_array[] = $jsroot . 'keyboardNavigation.js';
226

227
    $strings = array();
228
229
230
231
232
233
234
235
236
    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);
        }
237
238
    }

239
    $jsstrings = jsstrings();
Martyn Smith's avatar
Martyn Smith committed
240
    $themepaths = themepaths();
241

Richard Mansfield's avatar
Richard Mansfield committed
242
    foreach ($javascript as $jsfile) {
243
244
245
246
        // 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.
247
        if (strpos($jsfile, '/') === false) {
248
            $javascript_array[] = $jsroot . $jsfile . '.js';
249
            if (isset($jsstrings[$jsfile])) {
250
251
252
                foreach ($jsstrings[$jsfile] as $section => $tags) {
                    foreach ($tags as $tag) {
                        $strings[$tag] = get_raw_string($tag, $section);
253
254
255
                    }
                }
            }
Martyn Smith's avatar
Martyn Smith committed
256
257
            if (isset($themepaths[$jsfile])) {
                foreach ($themepaths[$jsfile] as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
258
                    $theme_list[$themepath] = $THEME->get_url($themepath);
Martyn Smith's avatar
Martyn Smith committed
259
260
                }
            }
261
262
        }
        else {
263
            // A .js file with a fully specified path
264
            $javascript_array[] = $wwwroot . $jsfile;
265
266
267
268
269
270
            // 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]);
271
                $name = substr($bits[3], 0, strpos($bits[3], '.js'));
272
273
                if (is_callable(array($pluginclass, 'jsstrings'))) {
                    $tempstrings = call_static_method($pluginclass, 'jsstrings', $name);
274
275
276
                    foreach ($tempstrings as $section => $tags) {
                        foreach ($tags as $tag) {
                            $strings[$tag] = get_raw_string($tag, $section);
277
278
                        }
                    }
Richard Mansfield's avatar
Richard Mansfield committed
279
                }
280
281
282
283
284
285
286
287
288
                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
289
290
291
                if (is_callable(array($pluginclass, 'themepaths'))) {
                    $tmpthemepaths = call_static_method($pluginclass, 'themepaths', $name);
                    foreach ($tmpthemepaths as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
292
                        $theme_list[$themepath] = $THEME->get_url($themepath);
Martyn Smith's avatar
Martyn Smith committed
293
294
                    }
                }
Martyn Smith's avatar
Martyn Smith committed
295
            }
Martyn Smith's avatar
Martyn Smith committed
296
        }
297
    }
298
299

    $javascript_array[] = $jsroot . 'mahara.js';
300
    if (get_config('developermode') & DEVMODE_DEBUGJS) {
301
        $javascript_array[] = $jsroot . 'debug.js';
302
303
304
305
    }
    if ((get_config('developermode') & DEVMODE_FIREBUGLITE)
        && isset($_SERVER['HTTP_USER_AGENT']) && false === stripos($_SERVER['HTTP_USER_AGENT'], 'gecko')) {
        $javascript_array[] = $jsroot . 'firebug/firebug.js';
306
    }
307

308
309
310
    foreach ($jsstrings['mahara'] as $section => $tags) {
        foreach ($tags as $tag) {
            $strings[$tag] = get_raw_string($tag, $section);
311
312
        }
    }
313
314
    if (isset($extraconfig['themepaths']) && is_array($extraconfig['themepaths'])) {
        foreach ($extraconfig['themepaths'] as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
315
            $theme_list[$themepath] = $THEME->get_url($themepath);
316
317
        }
    }
318

319
    $stringjs = '<script type="text/javascript">';
320
    $stringjs .= 'var strings = ' . json_encode($strings) . ';';
321
322
    $stringjs .= '</script>';

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

339
340
341
    // look for extra stylesheets
    if (isset($extraconfig['stylesheets']) && is_array($extraconfig['stylesheets'])) {
        foreach ($extraconfig['stylesheets'] as $extrasheet) {
342
            if ($sheets = $THEME->get_url($extrasheet, true)) {
Nigel McNie's avatar
Nigel McNie committed
343
                $stylesheets = array_merge($stylesheets, array_reverse(array_values($sheets)));
344
345
346
347
            }
        }
    }

348
    $smarty->assign('STRINGJS', $stringjs);
349

350
    $smarty->assign('STYLESHEETLIST', $stylesheets);
351
352
353
354
    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))); 
    }
355

356

357
358
359
360
    $sitename = get_config('sitename');
    if (!$sitename) {
       $sitename = 'Mahara';
    }
361
    $smarty->assign('sitename', $sitename);
362

Martyn Smith's avatar
Martyn Smith committed
363
    if (defined('TITLE')) {
364
        $smarty->assign('PAGETITLE', TITLE . ' - ' . $sitename);
365
        $smarty->assign('heading', TITLE);
Martyn Smith's avatar
Martyn Smith committed
366
367
    }
    else {
368
        $smarty->assign('PAGETITLE', $sitename);
Martyn Smith's avatar
Martyn Smith committed
369
370
    }

371
372
373
    if (defined('PUBLIC')) {
        $smarty->assign('PUBLIC', true);
    }
374
375
376
    if (defined('ADMIN')) {
        $smarty->assign('ADMIN', true);
    }
377
378
379
    if (defined('INSTITUTIONALADMIN')) {
        $smarty->assign('INSTITUTIONALADMIN', true);
    }
380

381
382
    $smarty->assign('LOGGEDIN', $USER->is_logged_in());
    if ($USER->is_logged_in()) {
383
        $smarty->assign('MAINNAV', main_nav());
384
    }
385
386
    else {
        $smarty->assign('sitedefaultlang', get_string('sitedefault', 'admin') . ' (' . 
387
                        get_string_from_language(get_config('lang'), 'thislanguage') . ')');
388
389
        $smarty->assign('LANGUAGES', get_languages());
    }
390

391
    $smarty->assign_by_ref('USER', $USER);
392
    $smarty->assign('SESSKEY', $USER->get('sesskey'));
393
    $smarty->assign_by_ref('JAVASCRIPT', $javascript_array);
394
    $smarty->assign_by_ref('HEADERS', $headers);
395
396
397
398
399
400
401
402
    if (get_config('siteclosed')) {
        if (get_config('disablelogin')) {
            $smarty->assign('SITECLOSED', get_string('siteclosedlogindisabled', 'mahara', get_config('wwwroot') . 'admin/upgrade.php'));
        }
        else {
            $smarty->assign('SITECLOSED', get_string('siteclosed'));
        }
    }
403

404
405
    if ((!isset($extraconfig['pagehelp']) || $extraconfig['pagehelp'] !== false)
        and $help = has_page_help()) {
406
407
408
        $smarty->assign('PAGEHELPNAME', $help[0]);
        $smarty->assign('PAGEHELPICON', $help[1]);
    }
409
    if (defined('GROUP')) {
410
        require_once('group.php');
411
412
        $group = group_current_group();
        $smarty->assign('GROUP', $group);
413
        $smarty->assign('GROUPNAV', group_get_menu_tabs());
414
        $smarty->assign('PAGEHEADING', hsc($group->name));
415
    }
416

Martyn Smith's avatar
Martyn Smith committed
417
    // ---------- sideblock stuff ----------
418
419
    $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
420
        if (get_config('installed') && !defined('ADMIN') && !defined('INSTITUTIONALADMIN')) {
421
422
423
424
            $data = site_menu();
            if (!empty($data)) {
                $smarty->assign('SITEMENU', site_menu());
                $SIDEBLOCKS[] = array(
425
                    'name'   => 'linksandresources',
426
427
428
429
430
431
432
                    'weight' => 10,
                    'data'   => $data,
                );
            }
        }

        if ($USER->is_logged_in() && defined('MENUITEM') && substr(MENUITEM, 0, 11) == 'myportfolio') {
Clare Lenihan's avatar
Clare Lenihan committed
433
            $SIDEBLOCKS[] = array(
434
435
436
                'name'   => 'selfsearch',
                'weight' => 0,
                'data'   => array(),
Clare Lenihan's avatar
Clare Lenihan committed
437
            );
438
            $SIDEBLOCKS[] = array(
439
440
                'name'   => 'tags',
                'id'     => 'sb-tags',
441
                'weight' => 0,
442
                'data'   => tags_sideblock(),
443
            );
Clare Lenihan's avatar
Clare Lenihan committed
444
        }
Clare Lenihan's avatar
Clare Lenihan committed
445

Richard Mansfield's avatar
Richard Mansfield committed
446
        if($USER->is_logged_in() && !defined('ADMIN') && !defined('INSTITUTIONALADMIN')) {
447
448
            $SIDEBLOCKS[] = array(
                'name'   => 'profile',
449
                'id'     => 'sb-profile',
450
451
452
                'weight' => -20,
                'data'   => profile_sideblock()
            );
453
454
455
            if (get_config('showonlineuserssideblock')) {
                $SIDEBLOCKS[] = array(
                    'name'   => 'onlineusers',
456
                    'id'     => 'sb-onlineusers',
457
458
459
460
                    'weight' => -10,
                    'data'   => onlineusers_sideblock(),
                );
            }
461
        }
Martyn Smith's avatar
Martyn Smith committed
462

Richard Mansfield's avatar
Richard Mansfield committed
463
464
465
        if(defined('GROUP')) {
            $SIDEBLOCKS[] = array(
                'name'   => 'group',
466
                'id'     => 'sb-groupnav',
Richard Mansfield's avatar
Richard Mansfield committed
467
468
469
470
471
472
                'weight' => -10,
                'data'   => group_sideblock()
            );
        }

        if (!$USER->is_logged_in()) {
473
            $SIDEBLOCKS[] = array(
474
475
                'name'   => 'login',
                'weight' => -10,
476
                'id'     => 'sb-loginbox',
477
478
479
                'data'   => array(
                    'loginform' => auth_generate_login_form(),
                ),
480
481
            );
        }
482

483
484
485
486
487
488
489
490
491
        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
492
493
        }

494
495
496
497
498
        if (isset($extraconfig['sideblocks']) && is_array($extraconfig['sideblocks'])) {
            foreach ($extraconfig['sideblocks'] as $sideblock) {
                $SIDEBLOCKS[] = $sideblock;
            }
        }
Martyn Smith's avatar
Martyn Smith committed
499

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

502
503
504
505
506
507
508
509
510
        // 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.
        $tmp = $SIDEBLOCKS;
        $SIDEBLOCKS = array(
            'left'  => array(),
            'right' => $tmp,
        );

511
        $smarty->assign('userauthinstance', $SESSION->get('authinstance'));
512
        $smarty->assign('MNETUSER', $SESSION->get('mnetuser'));
513
        $smarty->assign('SIDEBLOCKS', $SIDEBLOCKS);
514
        $smarty->assign('SIDEBARS', $sidebars);
515
516
517

        if ($USER->get('parentuser')) {
            $smarty->assign('USERMASQUERADING', true);
518
            $smarty->assign('masqueradedetails', get_string('youaremasqueradingas', 'mahara', hsc(display_name($USER))));
519
520
521
522
523
            $smarty->assign('becomeyouagain',
                ' <a href="' . hsc($wwwroot) . 'admin/users/changeuser.php?restore=1">'
                . get_string('becomeadminagain', 'admin', $USER->get('parentuser')->name)
                . '</a>');
        }
524
    }
Martyn Smith's avatar
Martyn Smith committed
525

526
527
528
    return $smarty;
}

529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552

/**
 * 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 = '';

    /**
     * A human-readable version of the theme name
     */
    public $displayname = '';

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

553
554
555
556
557
558
559
560
561
562
    /**
     * Directories where to look for templates by default
     */
    public $templatedirs = array();

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

563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
    /**
     * 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;
        }
        else if ($arg instanceof User) {
            $themename = $arg->get('theme');
        }
        else if (is_int($arg)) {
            $user = new User();
            $user->find_by_id($arg);
            $themename = $user->get('theme');
        }
        else {
            throw new SystemException("Argument to Theme::__construct was not a theme name, user object or user ID");
        }

        if (!$themename) {
            // Theme to show to when no theme has been suggested
625
626
627
            if (!$themename = get_config('theme')) {
                $themename = 'raw';
            }
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
        }
        $this->init_theme($themename);
    }

    /**
     * Given a theme name, reads in all config and sets fields on this object
     */
    private function init_theme($themename) {
        if (!preg_match('/^[a-zA-Z0-9_-]+$/', $themename)) {
            throw new SystemException("Theme name is in invalid form: '$themename'");
        }

        $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)) {
657
            $this->displayname = $this->basename;
658
659
660
661
662
        }
        if (!isset($theme->parent) || !$theme->parent) {
            $theme->parent = 'raw';
        }

663
664
665
        $this->templatedirs[] = get_config('docroot') . 'theme/' . $this->basename . '/templates/';
        $this->inheritance[]  = $this->basename;

666
667
668
669
670
671
672
673
        // 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) {
674
                if (!isset($this->$key) || !$this->$key) {
675
676
677
                    $this->$key = $value;
                }
            }
678
679
            $this->templatedirs[] = get_config('docroot') . 'theme/' . $currenttheme . '/templates/';
            $this->inheritance[]  = $currenttheme;
680
681
682
        }
    }

683
684
685
    /**
     * stuff
     */
686
687
    public function get_url($filename, $all=false, $plugindirectory='') {
        return $this->_get_path($filename, $all, $plugindirectory, get_config('wwwroot'));
688
689
    }

690
691
    public function get_path($filename, $all=false, $plugindirectory='') {
        return $this->_get_path($filename, $all, $plugindirectory, get_config('docroot'));
692
693
    }

694
    private function _get_path($filename, $all, $plugindirectory, $returnprefix) {
695
        $list = array();
696
        $plugindirectory = ($plugindirectory && substr($plugindirectory, -1) != DIRECTORY_SEPARATOR) ? $plugindirectory . DIRECTORY_SEPARATOR : $plugindirectory;
697
698

        foreach ($this->inheritance as $themedir) {
699
            if (is_readable(get_config('docroot') . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename)) {
700
                if ($all) {
701
                    $list[$themedir] = $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
702
703
                }
                else {
704
                    return $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
705
706
707
708
709
710
711
712
                }
            }
        }
        if ($all) {
            return $list;
        }

        $extra = '';
713
714
        if ($plugindirectory) {
            $extra = ", plugindir $plugindirectory";
715
716
        }
        log_debug("Missing file in theme {$this->basename}{$extra}: $filename");
717
        return $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
718
719
    }

720
721
722
}


723
724
/** 
 * Returns the lists of strings used in the .js files
725
 * @return array                   
726
727
 */

728
function jsstrings() {
Martyn Smith's avatar
Martyn Smith committed
729
    return array(
730
731
732
       'mahara' => array(                        // js file
            'mahara' => array(                   // section
                'namedfieldempty',               // string name
733
                'processing',
734
735
736
                'requiredfieldempty',
                'unknownerror',
                'loading',
Martyn Smith's avatar
Martyn Smith committed
737
                'showtags',
738
739
                'unreadmessages',
                'unreadmessage',
740
741
                'pendingfriend',
                'pendingfriends',
742
                'couldnotgethelp',
743
744
745
746
747
748
                'password',
                'username',
                'login',
                'sessiontimedout',
                'loginfailed',
                'home',
749
                'youhavenottaggedanythingyet',
750
            ),
751
752
        ),
        'tablerenderer' => array(
753
754
755
756
757
758
            'mahara' => array(
                'firstpage',
                'nextpage',
                'prevpage',
                'lastpage',
            )
759
        ),
760
        'friends' => array(
761
            'group' => array(
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
                'confirmremovefriend',
                'seeallviews',
                'noviewstosee',
                'sendmessage',
                'whymakemeyourfriend',
                'approverequest',
                'denyrequest',
                'pending',
                'removefromfriendslist',
                'views',
                'trysearchingforfriends',
                'nobodyawaitsfriendapproval',
                'sendfriendrequest',
                'addtomyfriends',
                'friendshiprequested',
                'userdoesntwantfriends',
                'existingfriend',
                'nosearchresultsfound',
780
                'reason',
781
                'requestfriendship',
782
                'cancel',
783
784
            ),
        ),
785
786
787
        'views' => array(
            'view' => array(
                'confirmdeleteblockinstance',
788
                'blocksinstructionajax',
789
                'Configure',
790
791
            ),
        ),
792
793
794
795
796
797
798
799
800
        'adminusersearch' => array(
            'admin' => array(
                'suspenduser',
                'suspensionreason',
            ),
            'mahara' => array(
                'cancel',
            ),
        ),
801
802
803
804
805
806
807
808
809
810
        'feedbacklist' => array(
            'view' => array(
                'feedbackattachmessage',
                'makeprivate',
                'thisfeedbackisprivate',
                'thisfeedbackispublic',
                'attachment',
                'nopublicfeedback',
            ),
        ),
Martyn Smith's avatar
Martyn Smith committed
811
812
813
    );
}

Martyn Smith's avatar
Martyn Smith committed
814
function themepaths() {
815
816
817
818
819
820
821
822
823

    static $paths;
    if (empty($paths)) {
        $paths = array(
            'mahara' => array(
                'images/icon_close.gif',
                'images/failure.gif',
                'images/loading.gif',
                'images/success.gif',
824
                'images/icon_problem.gif',
825
                'images/icon_help.gif',
826
                'style/js.css',
827
828
829
830
            ),
        );
    }
    return $paths;
Martyn Smith's avatar
Martyn Smith committed
831
832
}

833
834
835
836
837
838
/** 
 * Takes an array of string identifiers and returns an array of the
 * corresponding strings, quoted for use in inline javascript here
 * docs.
 */

839
840
841
842
function quotestrings($strings) {
    $qstrings = array();
    foreach ($strings as $section => $tags) {
        foreach ($tags as $tag) {
843
            $qstrings[$tag] = json_encode(get_string($tag, $section));
844
        }
845
    }
846
    return $qstrings;
847
848
}

849
850
851
852
853
854
855
/** 
 * 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() {
856
857
858
    global $THEME;
    log_warn("theme_setup() is deprecated - please use the global \$THEME object instead");
    return $THEME;
859
860
861
862
863
864
865
866
}

/** 
 * 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
 */
867
function theme_get_url($location, $pluginlocation='', $all = false) {
868
869
870
871
872
873
    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);
874
    }
875
    return $THEME->get_url($location, $all, $plugintype, $pluginname);
876
877
}

878
879
880
881
882
883
/** 
 * This function returns the full path to an image
 * Always use it to get image paths
 * @param $imagelocation path to image relative to theme/$theme/static/
 * @param $pluginlocation path to plugin relative to docroot
 */
884
function theme_get_path($location, $pluginlocation='', $all=false) {
885
886
887
888
889
890
    global $THEME;
    log_warn("theme_get_path() is deprecated: Use \$THEME->get_path() instead");
    $plugintype = $pluginname = '';
    if ($pluginlocation) {
        list($plugintype, $pluginname) = explode('/', $pluginlocation);
        $pluginname = substr($pluginname, 0, -1);
891
    }
892
    return $THEME->get_path($location, $all, $plugintype, $pluginname);
893
894
}

895
896
897
898
899
/**
 * This function sends headers suitable for all JSON returning scripts.
 *
 */
function json_headers() {
900
    // @todo Catalyst IT Ltd
901
902
    // header('Content-type: text/x-json');
    header('Content-type: text/plain');
Martyn Smith's avatar
Martyn Smith committed
903
    header('Pragma: no-cache');
904
905
}

Richard Mansfield's avatar
Richard Mansfield committed
906
/**
907
 * This function sends a JSON message, and ends the script.
Richard Mansfield's avatar
Richard Mansfield committed
908
 *
909
910
911
912
913
914
915
916
 * Scripts receiving replies will recieve a JSON array with two fields:
 *
 *  - error: True or false depending on whether the request was successful
 *  - message: JSON data representing a message sent back from the script
 *
 * @param boolean $error   Whether the script ended in an error or not
 * @param string  $message A message to pass back to the user, can be an
 *                         array of JSON data
Richard Mansfield's avatar
Richard Mansfield committed
917
 */
918
function json_reply($error, $message, $returncode=0) {
Richard Mansfield's avatar
Richard Mansfield committed
919
    json_headers();
920
    echo json_encode(array('error' => $error, 'message' => $message, 'returnCode' => $returncode));
921
    perf_to_log();
Richard Mansfield's avatar
Richard Mansfield committed
922
923
924
    exit;
}

925
function _param_retrieve($name) {
926
927
928
929
930
931
932
    // prefer post
    if (isset($_POST[$name])) {
        $value = $_POST[$name];
    } 
    else if (isset($_GET[$name])) {
        $value = $_GET[$name];
    }
933
    else if (func_num_args() == 2) {
934
935
936
        $php_work_around = func_get_arg(1);
        return array($php_work_around, true);
    }
937
    else {
938
939
940
        throw new ParameterException("Missing parameter '$name' and no default supplied");
    }

941
    return array($value, false);
942
943
}

Martyn Smith's avatar
Martyn Smith committed
944
945
946
947
948
949
950
951
952
953
954
/**
 * This function returns a GET or POST parameter with optional default.  If the
 * default isn't specified and the parameter hasn't been sent, a
 * ParameterException exception is thrown
 *
 * @param string The GET or POST parameter you want returned
 * @param mixed [optional] the default value for this parameter
 *
 * @return string The value of the parameter
 *
 */
Martyn Smith's avatar
Martyn Smith committed
955
function param_variable($name) {
956
957
958
    $args = func_get_args();
    list ($value) = call_user_func_array('_param_retrieve', $args);
    return $value;
Martyn Smith's avatar
Martyn Smith committed
959
960
961
962
963
964
965
966
967
968
969
}

/**
 * This function returns a GET or POST parameter as an integer with optional
 * default.  If the default isn't specified and the parameter hasn't been sent,
 * a ParameterException exception is thrown. Likewise, if the parameter isn't a
 * valid integer, a ParameterException exception is thrown
 *
 * @param string The GET or POST parameter you want returned
 * @param mixed [optional] the default value for this parameter
 *
Nigel McNie's avatar
Nigel McNie committed
970
 * @return int The value of the parameter
Martyn Smith's avatar
Martyn Smith committed
971
972
 *
 */
Martyn Smith's avatar
Martyn Smith committed
973
function param_integer($name) {
974
975
976
977
978
979
    $args = func_get_args();

    list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);

    if ($defaultused) {
        return $value;
Martyn Smith's avatar
Martyn Smith committed
980
981
982
983
984
    }

    if (preg_match('/^\d+$/',$value)) {
        return (int)$value;
    }
985
986
987
    else if ($value == '' && isset($args[1])) {
        return $args[1];
    }
Martyn Smith's avatar
Martyn Smith committed
988

989
    throw new ParameterException("The '$name' parameter is not an integer");
Martyn Smith's avatar
Martyn Smith committed
990
991
}

Martyn Smith's avatar
Martyn Smith committed
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
/**
 * This function returns a GET or POST parameter as an alpha string with optional
 * default.  If the default isn't specified and the parameter hasn't been sent,
 * a ParameterException exception is thrown. Likewise, if the parameter isn't a
 * valid alpha string, a ParameterException exception is thrown
 *
 * Valid characters are a-z and A-Z
 *
 * @param string The GET or POST parameter you want returned
 * @param mixed [optional] the default value for this parameter
 *
 * @return string The value of the parameter
 *
 */
function param_alpha($name) {
1007
1008
1009
1010
1011
1012
    $args = func_get_args();

    list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);

    if ($defaultused) {
        return $value;
Martyn Smith's avatar
Martyn Smith committed
1013
1014
    }

Richard Mansfield's avatar
Richard Mansfield committed
1015
    if (preg_match('/^[a-zA-Z]+$/',$value)) {
Martyn Smith's avatar
Martyn Smith committed
1016
1017
1018
        return $value;
    }

1019
    throw new ParameterException("The '$name' parameter is not alphabetical only");
Martyn Smith's avatar
Martyn Smith committed
1020
1021
}

1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
/**
 * This function returns a GET or POST parameter as an alphanumeric string with optional
 * default.  If the default isn't specified and the parameter hasn't been sent,
 * a ParameterException exception is thrown. Likewise, if the parameter isn't a
 * valid alpha string, a ParameterException exception is thrown
 *
 * Valid characters are a-z and A-Z and 0-9
 *
 * @param string The GET or POST parameter you want returned
 * @param mixed [optional] the default value for this parameter
 *
 * @return string The value of the parameter
 *
 */
function param_alphanum($name) {
    $args = func_get_args();

    list ($value, $defaultused) = call_user_func_array('_param_retrieve', $args);

    if ($defaultused) {
        return $value;
    }

    if (preg_match('/^[a-zA-Z0-9]+$/',$value)) {
        return $value;
    }

1049
    throw new ParameterException("The '$name' parameter is not alphanumeric only");
1050
1051
}

1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
/**
 * This function returns a GET or POST parameter as an alphanumeric string with optional
 * default.  If the default isn't specified and the parameter hasn't been sent,
 * a ParameterException exception is thrown. Likewise, if the parameter isn't a
 * valid alpha string, a ParameterException exception is thrown
 *
 * Valid characters are a-z and A-Z and 0-9 and _ and - and .
 *
 * @param string The GET or POST parameter you want returned
 * @param mixed [optional] the default value for this parameter
 *
 * @return string The value of the parameter
 *
 */
function param_alphanumext($name) {
    $args = func_get_args();

    list