web.php 103 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
                $extrasetup = isset($extraconfig['tinymcesetup']) ? $extraconfig['tinymcesetup'] : '';
107

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

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

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

154
                $headers[] = <<<EOF
155
156
157
158
<script type="text/javascript">
tinyMCE.init({
    button_tile_map: true,
    {$tinymce_config}
159
    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]",
160
    urlconverter_callback : "custom_urlconvert",
161
    language: '{$language}',
162
    directionality: "{$tinymce_langdir}",
163
    content_css : {$content_css},
164
    //document_base_url: {$jswwwroot},
165
    remove_script_host: false,
166
167
168
    relative_urls: false,
    setup: function(ed) {
        ed.onInit.add(function(ed) {
169
            if (typeof(editor_to_focus) == 'string' && ed.editorId == editor_to_focus) {
170
171
172
                ed.focus();
            }
        });
173
        {$extrasetup}
174
    }
175
});
176
function custom_urlconvert (u, n, e) {
177
  // Don't convert the url on the skype status buttons.
178
179
  if (u.indexOf('skype:') == 0) {
      return u;
180
  }
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  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;
195
}
196
197
198
</script>

EOF;
199
200
201
202
203
204
205
                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]);
206
            }
207
        }
208
209
        // Load jquery first, so that it doesn't break Mochikit
        if (($key = array_search('jquery', $check)) !== false) {
210
            $jquery = (get_config('developermode') & DEVMODE_UNPACKEDJS) ? 'jquery-1.5.2.js' : 'jquery-1.5.2.min.js';
211
212
213
214
215
            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]);
        }
216
    }
217

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

231
    $strings = array();
232
233
234
235
236
237
238
239
240
    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);
        }
241
242
    }

243
    $jsstrings = jsstrings();
Martyn Smith's avatar
Martyn Smith committed
244
    $themepaths = themepaths();
245

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

    $javascript_array[] = $jsroot . 'mahara.js';
308
    if (get_config('developermode') & DEVMODE_DEBUGJS) {
309
        $javascript_array[] = $jsroot . 'debug.js';
310
    }
311

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

323
    $stringjs = '<script type="text/javascript">';
324
    $stringjs .= 'var strings = ' . json_encode($strings) . ';';
325
326
    $stringjs .= '</script>';

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

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

352
    // Include rtl.css for right-to-left langs
353
    if ($langdirection == 'rtl') {
354
        $smarty->assign('LANGDIRECTION', 'rtl');
355
356
357
358
359
        if ($rtlsheets = $THEME->get_url('style/rtl.css', true)) {
            $stylesheets = array_merge($stylesheets, array_reverse($rtlsheets));
        }
    }

360
    $smarty->assign('STRINGJS', $stringjs);
361

362
    $smarty->assign('STYLESHEETLIST', $stylesheets);
363
364
365
366
    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))); 
    }
367

368

369
370
371
372
    $sitename = get_config('sitename');
    if (!$sitename) {
       $sitename = 'Mahara';
    }
373
    $smarty->assign('sitename', $sitename);
374

Martyn Smith's avatar
Martyn Smith committed
375
    if (defined('TITLE')) {
376
        $smarty->assign('PAGETITLE', TITLE . ' - ' . $sitename);
377
        $smarty->assign('heading', TITLE);
Martyn Smith's avatar
Martyn Smith committed
378
379
    }
    else {
380
        $smarty->assign('PAGETITLE', $sitename);
Martyn Smith's avatar
Martyn Smith committed
381
382
    }

383
384
385
    if (function_exists('local_header_top_content')) {
        $smarty->assign('SITETOP', local_header_top_content());
    }
386
387
388
    if (defined('PUBLIC')) {
        $smarty->assign('PUBLIC', true);
    }
389
390
391
    if (defined('ADMIN')) {
        $smarty->assign('ADMIN', true);
    }
392
393
394
    if (defined('INSTITUTIONALADMIN')) {
        $smarty->assign('INSTITUTIONALADMIN', true);
    }
395

396
397
    $smarty->assign('LOGGEDIN', $USER->is_logged_in());
    if ($USER->is_logged_in()) {
398
        global $SELECTEDSUBNAV; // It's evil, but rightnav & mainnav stuff are now in different templates.
399
        $smarty->assign('MAINNAV', main_nav());
400
        $smarty->assign('RIGHTNAV', right_nav());
401
        $smarty->assign('SELECTEDSUBNAV', $SELECTEDSUBNAV);
402
    }
403
404
    else {
        $smarty->assign('sitedefaultlang', get_string('sitedefault', 'admin') . ' (' . 
405
                        get_string_from_language(get_config('lang'), 'thislanguage') . ')');
406
407
        $smarty->assign('LANGUAGES', get_languages());
    }
408
    $smarty->assign('FOOTERMENU', footer_menu());
409

410
    $smarty->assign_by_ref('USER', $USER);
411
    $smarty->assign('SESSKEY', $USER->get('sesskey'));
412
    $smarty->assign_by_ref('JAVASCRIPT', $javascript_array);
413
    $smarty->assign_by_ref('HEADERS', $headers);
414
415
    $siteclosedforupgrade = get_config('siteclosed');
    if ($siteclosedforupgrade && get_config('disablelogin')) {
416
        $smarty->assign('SITECLOSED', 'logindisabled');
417
418
    }
    else if ($siteclosedforupgrade || get_config('siteclosedbyadmin')) {
419
        $smarty->assign('SITECLOSED', 'loginallowed');
420
    }
421

422
423
    if ((!isset($extraconfig['pagehelp']) || $extraconfig['pagehelp'] !== false)
        and $help = has_page_help()) {
424
425
426
        $smarty->assign('PAGEHELPNAME', $help[0]);
        $smarty->assign('PAGEHELPICON', $help[1]);
    }
427
    if (defined('GROUP')) {
428
        require_once('group.php');
429
430
        $group = group_current_group();
        $smarty->assign('GROUP', $group);
431
432
433
434
        if (!defined('NOGROUPMENU')) {
            $smarty->assign('SUBPAGENAV', group_get_menu_tabs());
            $smarty->assign('PAGEHEADING', $group->name);
        }
435
    }
436

Martyn Smith's avatar
Martyn Smith committed
437
    // ---------- sideblock stuff ----------
438
439
    $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
440
        if (get_config('installed') && !defined('ADMIN') && !defined('INSTITUTIONALADMIN')) {
441
442
443
444
            $data = site_menu();
            if (!empty($data)) {
                $smarty->assign('SITEMENU', site_menu());
                $SIDEBLOCKS[] = array(
445
                    'name'   => 'linksandresources',
446
447
448
449
450
451
                    'weight' => 10,
                    'data'   => $data,
                );
            }
        }

452
453
        if ($USER->is_logged_in() && defined('MENUITEM') &&
            (substr(MENUITEM, 0, 11) == 'myportfolio' || substr(MENUITEM, 0, 7) == 'content')) {
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
            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
469
        }
Clare Lenihan's avatar
Clare Lenihan committed
470

Richard Mansfield's avatar
Richard Mansfield committed
471
        if($USER->is_logged_in() && !defined('ADMIN') && !defined('INSTITUTIONALADMIN')) {
472
473
            $SIDEBLOCKS[] = array(
                'name'   => 'profile',
474
                'id'     => 'sb-profile',
475
476
477
                'weight' => -20,
                'data'   => profile_sideblock()
            );
478
479
480
            if (get_config('showonlineuserssideblock')) {
                $SIDEBLOCKS[] = array(
                    'name'   => 'onlineusers',
481
                    'id'     => 'sb-onlineusers',
482
483
484
485
                    'weight' => -10,
                    'data'   => onlineusers_sideblock(),
                );
            }
486
        }
Martyn Smith's avatar
Martyn Smith committed
487

Richard Mansfield's avatar
Richard Mansfield committed
488
489
490
        if(defined('GROUP')) {
            $SIDEBLOCKS[] = array(
                'name'   => 'group',
491
                'id'     => 'sb-groupnav',
Richard Mansfield's avatar
Richard Mansfield committed
492
493
494
495
496
                'weight' => -10,
                'data'   => group_sideblock()
            );
        }

497
        if (!$USER->is_logged_in() && !(get_config('siteclosed') && get_config('disablelogin'))) {
498
            $SIDEBLOCKS[] = array(
499
500
                'name'   => 'login',
                'weight' => -10,
501
                'id'     => 'sb-loginbox',
502
503
504
                'data'   => array(
                    'loginform' => auth_generate_login_form(),
                ),
505
506
            );
        }
507

508
509
510
511
512
513
514
515
516
        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
517
518
        }

519
520
521
522
523
        if (isset($extraconfig['sideblocks']) && is_array($extraconfig['sideblocks'])) {
            foreach ($extraconfig['sideblocks'] as $sideblock) {
                $SIDEBLOCKS[] = $sideblock;
            }
        }
Martyn Smith's avatar
Martyn Smith committed
524

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

527
528
529
        // 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.
530
        $sidebars = $sidebars && !empty($SIDEBLOCKS);
531
        $SIDEBLOCKS = array('left' => array(), 'right' => $SIDEBLOCKS);
532

533
        $smarty->assign('userauthinstance', $SESSION->get('authinstance'));
534
        $smarty->assign('MNETUSER', $SESSION->get('mnetuser'));
535
        $smarty->assign('SIDEBLOCKS', $SIDEBLOCKS);
536
        $smarty->assign('SIDEBARS', $sidebars);
537

538
539
540
541
    }

    if ($USER->get('parentuser')) {
        $smarty->assign('USERMASQUERADING', true);
542
        $smarty->assign('masqueradedetails', get_string('youaremasqueradingas', 'mahara', display_name($USER)));
543
544
        $smarty->assign('becomeyouagain',
            ' <a href="' . hsc($wwwroot) . 'admin/users/changeuser.php?restore=1">'
545
            . get_string('becomeadminagain', 'admin', hsc($USER->get('parentuser')->name))
546
            . '</a>');
547
    }
Martyn Smith's avatar
Martyn Smith committed
548

549
550
551
    return $smarty;
}

552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575

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

576
577
578
579
580
581
582
583
584
585
    /**
     * Directories where to look for templates by default
     */
    public $templatedirs = array();

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

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
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
    /**
     * 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
648
649
650
            if (!$themename = get_config('theme')) {
                $themename = 'raw';
            }
651
        }
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666

        // check the validity of the name
        if ($this->name_is_valid($themename)) {
            $this->init_theme($themename);
        } else {
            throw new SystemException("Theme name is in invalid form: '$themename'");
        }
    }

    /**
     * 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);
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
    }

    /**
     * Given a theme name, reads in all config and sets fields on this object
     */
    private function init_theme($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)) {
690
            $this->displayname = $this->basename;
691
692
693
694
695
        }
        if (!isset($theme->parent) || !$theme->parent) {
            $theme->parent = 'raw';
        }

696
697
698
        $this->templatedirs[] = get_config('docroot') . 'theme/' . $this->basename . '/templates/';
        $this->inheritance[]  = $this->basename;

699
700
701
702
703
704
705
706
        // 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) {
707
                if (!isset($this->$key) || !$this->$key) {
708
709
710
                    $this->$key = $value;
                }
            }
711
712
            $this->templatedirs[] = get_config('docroot') . 'theme/' . $currenttheme . '/templates/';
            $this->inheritance[]  = $currenttheme;
713
714
715
        }
    }

716
717
718
    /**
     * stuff
     */
719
720
    public function get_url($filename, $all=false, $plugindirectory='') {
        return $this->_get_path($filename, $all, $plugindirectory, get_config('wwwroot'));
721
722
    }

723
724
    public function get_path($filename, $all=false, $plugindirectory='') {
        return $this->_get_path($filename, $all, $plugindirectory, get_config('docroot'));
725
726
    }

727
    private function _get_path($filename, $all, $plugindirectory, $returnprefix) {
728
        $list = array();
729
        $plugindirectory = ($plugindirectory && substr($plugindirectory, -1) != '/') ? $plugindirectory . '/' : $plugindirectory;
730
731

        foreach ($this->inheritance as $themedir) {
732
            if (is_readable(get_config('docroot') . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename)) {
733
                if ($all) {
734
                    $list[$themedir] = $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
735
736
                }
                else {
737
                    return $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
738
739
740
741
742
743
744
745
                }
            }
        }
        if ($all) {
            return $list;
        }

        $extra = '';
746
747
        if ($plugindirectory) {
            $extra = ", plugindir $plugindirectory";
748
749
        }
        log_debug("Missing file in theme {$this->basename}{$extra}: $filename");
750
        return $returnprefix . $plugindirectory . 'theme/' . $themedir . '/static/' . $filename;
751
752
    }

753
754
755
}


756
757
/** 
 * Returns the lists of strings used in the .js files
758
 * @return array                   
759
760
 */

761
function jsstrings() {
Martyn Smith's avatar
Martyn Smith committed
762
    return array(
763
764
765
       'mahara' => array(                        // js file
            'mahara' => array(                   // section
                'namedfieldempty',               // string name
766
                'processing',
767
768
769
                'requiredfieldempty',
                'unknownerror',
                'loading',
Martyn Smith's avatar
Martyn Smith committed
770
                'showtags',
771
772
                'unreadmessages',
                'unreadmessage',
773
774
                'pendingfriend',
                'pendingfriends',
775
                'couldnotgethelp',
776
777
778
779
780
781
                'password',
                'username',
                'login',
                'sessiontimedout',
                'loginfailed',
                'home',
782
                'youhavenottaggedanythingyet',
783
            ),
784
785
        ),
        'tablerenderer' => array(
786
787
788
789
790
791
            'mahara' => array(
                'firstpage',
                'nextpage',
                'prevpage',
                'lastpage',
            )
792
        ),
793
        'friends' => array(
794
            'group' => array(
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
                'confirmremovefriend',
                'seeallviews',
                'noviewstosee',
                'sendmessage',
                'whymakemeyourfriend',
                'approverequest',
                'denyrequest',
                'pending',
                'removefromfriendslist',
                'views',
                'trysearchingforfriends',
                'nobodyawaitsfriendapproval',
                'sendfriendrequest',
                'addtomyfriends',
                'friendshiprequested',
                'userdoesntwantfriends',
                'existingfriend',
                'nosearchresultsfound',
813
                'reason',
814
                'requestfriendship',
815
                'cancel',
816
817
            ),
        ),
818
819
820
        'views' => array(
            'view' => array(
                'confirmdeleteblockinstance',
821
                'blocksinstructionajax',
822
                'Configure',
823
824
            ),
        ),
825
826
827
828
829
830
831
832
833
        'adminusersearch' => array(
            'admin' => array(
                'suspenduser',
                'suspensionreason',
            ),
            'mahara' => array(
                'cancel',
            ),
        ),
Martyn Smith's avatar
Martyn Smith committed
834
835
836
    );
}

Martyn Smith's avatar
Martyn Smith committed
837
function themepaths() {
838
839
840
841
842
843

    static $paths;
    if (empty($paths)) {
        $paths = array(
            'mahara' => array(
                'images/icon_close.gif',
844
                'images/edit.gif',
845
846
847
                'images/failure.gif',
                'images/loading.gif',
                'images/success.gif',
848
                'images/icon_problem.gif',
849
                'images/icon_help.gif',
850
                'style/js.css',
851
852
853
854
            ),
        );
    }
    return $paths;
Martyn Smith's avatar
Martyn Smith committed
855
856
}

857
858
859
860
861
862
/** 
 * Takes an array of string identifiers and returns an array of the
 * corresponding strings, quoted for use in inline javascript here
 * docs.
 */

863
864
865
866
function quotestrings($strings) {
    $qstrings = array();
    foreach ($strings as $section => $tags) {
        foreach ($tags as $tag) {
867
            $qstrings[$tag] = json_encode(get_string($tag, $section));
868
        }
869
    }
870
    return $qstrings;
871
872
}

873
874
875
876
877
878
879
/** 
 * 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() {
880
881
882
    global $THEME;
    log_warn("theme_setup() is deprecated - please use the global \$THEME object instead");
    return $THEME;
883
884
885
886
887
888
889
890
}

/** 
 * 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
 */
891
function theme_get_url($location, $pluginlocation='', $all = false) {
892
893
894
895
896
897
    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);
898
    }
899
    return $THEME->get_url($location, $all, $plugintype, $pluginname);
900
901
}

902
903
904
905
906
907
/** 
 * 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
 */
908
function theme_get_path($location, $pluginlocation='', $all=false) {
909
910
911
912
913
914
    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);
915
    }
916
    return $THEME->get_path($location, $all, $plugintype, $pluginname);
917
918
}

919
920
921
922
923
/**
 * This function sends headers suitable for all JSON returning scripts.
 *
 */
function json_headers() {
924
    // @todo Catalyst IT Ltd
925
926
    // header('Content-type: text/x-json');
    header('Content-type: text/plain');
Martyn Smith's avatar
Martyn Smith committed
927
    header('Pragma: no-cache');
928
929
}

Richard Mansfield's avatar
Richard Mansfield committed
930
/**
931
 * This function sends a JSON message, and ends the script.
Richard Mansfield's avatar
Richard Mansfield committed
932
 *
933
934
935
936
937
938
939
940
 * 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
941
 */
942
function json_reply($error, $message, $returncode=0) {
Richard Mansfield's avatar
Richard Mansfield committed
943
    json_headers();
944
    echo json_encode(array('error' => $error, 'message' => $message, 'returnCode' => $returncode));
945
    perf_to_log();
Richard Mansfield's avatar
Richard Mansfield committed
946
947
948
    exit;
}

949
function _param_retrieve($name) {
950
951
952
953
954
955
956
    // prefer post
    if (isset($_POST[$name])) {
        $value = $_POST[$name];
    } 
    else if (isset($_GET[$name])) {
        $value = $_GET[$name];
    }
957
    else if (func_num_args() == 2) {
958
959
960
        $php_work_around = func_get_arg(1);
        return array($php_work_around, true);
    }
961
    else {
962
963
964
        throw new ParameterException("Missing parameter '$name' and no default supplied");
    }

965
    return array($value, false);
966
967
}

Martyn Smith's avatar
Martyn Smith committed
968
969
970
971
972
973
974
975
976
977
978
/**
 * 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
979
function param_variable($name) {
980
981
982
    $args = func_get_args();
    list ($value) = call_user_func_array('_param_retrieve', $args);
    return $value;
Martyn Smith's avatar
Martyn Smith committed
983
984
985
986
987
988
989
990
991
992
993
}

/**
 * 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
994
 * @return int The value of the parameter
Martyn Smith's avatar
Martyn Smith committed
995
996
 *
 */
Martyn Smith's avatar
Martyn Smith committed
997
function param_integer($name) {
998
999
1000
1001
1002
1003
    $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
1004
1005
1006
1007
1008
    }

    if (preg_match('/^\d+$/',$value)) {
        return (int)$value;
    }
1009
1010
1011
    else if ($value == '' && isset($args[1])) {
        return $args[1];
    }
Martyn Smith's avatar
Martyn Smith committed
1012

1013
    throw new ParameterException("The '$name' parameter is not an integer");
Martyn Smith's avatar
Martyn Smith committed
1014
1015
}

1016
1017