web.php 170 KB
Newer Older
1 2 3 4 5
<?php
/**
 *
 * @package    mahara
 * @subpackage core
6
 * @author     Catalyst IT Ltd
7 8
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
 * @copyright  For copyright information on Mahara, please see the README file distributed with this software.
9 10 11 12 13 14
 * @copyright  (C) portions from Moodle, (C) Martin Dougiamas http://dougiamas.com
 */

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


15 16 17
function smarty_core() {
    require_once 'dwoo/dwoo/dwooAutoload.php';
    require_once 'dwoo/mahara/Dwoo_Mahara.php';
18

19
    return new Dwoo_Mahara();
20 21 22
}


23 24 25 26 27 28 29 30 31

/**
 * Function to set an optional page icon. Mahara uses fontawesome for icons by default,
 * (http://fortawesome.github.io/Font-Awesome/icons/) but this can be overridden at the theme
 * level by supplying a different icon font + css.
 *
 * @param Smarty | an initialized smarty object
 * @param String | the name of the icon to include (eg "icon-university")
 */
Pat Kira's avatar
Pat Kira committed
32
function setpageicon($smarty, $icon) {
33 34 35 36 37 38
    $smarty->assign('pageicon', 'icon ' . $icon);
}



/**
39 40
 * Helper function (called by smarty()) to determine what stylesheets to include
 * on the page (based on constants, global variables, and $extraconfig)
41
 *
42 43
 * @param $stylesheets Stylesheets we already know we're going to need
 * @param $extraconfig Extra configuration passed to smarty()
44 45 46
 * @return array
 */

Pat Kira's avatar
Pat Kira committed
47
function get_stylesheets_for_current_page($stylesheets, $extraconfig) {
48 49 50 51 52 53 54

    global $USER, $SESSION, $THEME, $HEADDATA, $langselectform;

    // stylesheet set up - if we're in a plugin also get its stylesheet
    $allstylesheets = $THEME->get_url('style/style.css', true);

    // determine if we want to include the parent css
Pat Kira's avatar
Pat Kira committed
55
    if (isset($THEME->overrideparentcss) && $THEME->overrideparentcss && $THEME->parent) {
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
        unset($allstylesheets[$THEME->parent]);
    }

    $stylesheets = array_merge($stylesheets, array_reverse(array_values($allstylesheets)));

    if (defined('SECTION_PLUGINTYPE') && defined('SECTION_PLUGINNAME') && SECTION_PLUGINTYPE != 'core') {
        if ($pluginsheets = $THEME->get_url('style/style.css', true, SECTION_PLUGINTYPE . '/' . SECTION_PLUGINNAME)) {
            $stylesheets = array_merge($stylesheets, array_reverse($pluginsheets));
        }
    }

    if ($adminsection = in_admin_section()) {
        if ($adminsheets = $THEME->get_url('style/admin.css', true)) {
            $stylesheets = array_merge($stylesheets, array_reverse($adminsheets));
        }
    }

    if (get_config('developermode') & DEVMODE_DEBUGCSS) {
        $stylesheets[] = get_config('wwwroot') . 'theme/debug.css';
    }

    // look for extra stylesheets
    if (isset($extraconfig['stylesheets']) && is_array($extraconfig['stylesheets'])) {
        foreach ($extraconfig['stylesheets'] as $extrasheet) {
            if ($sheets = $THEME->get_url($extrasheet, true)) {
                $stylesheets = array_merge($stylesheets, array_reverse(array_values($sheets)));
            }
        }
    }
85 86 87 88

    // Only add additional stylesheets when configurable theme is set.
    if ($THEME->basename == 'custom') {
        $sheets = $THEME->additional_stylesheets();
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
        $stylesheets = array_merge($stylesheets, $sheets);
    }

    // Give the skin a chance to affect the page
    if (!empty($extraconfig['skin'])) {
        require_once(get_config('docroot').'/lib/skin.php');
        $skinobj = new Skin($extraconfig['skin']['skinid']);
        $viewid = isset($extraconfig['skin']['viewid']) ? $extraconfig['skin']['viewid'] : null;
        $stylesheets = array_merge($stylesheets, $skinobj->get_stylesheets($viewid));
    }

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

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

    $stylesheets = append_version_number($stylesheets);

    return $stylesheets;
}

115 116 117 118 119 120 121 122 123
/**
* True if we are not in admin, institution or admin section
*/
function user_personal_section() {
    $usersection = !defined('ADMIN') && !defined('STAFF') && !defined('INSTITUTIONALADMIN') &&
        !defined('INSTITUTIONALSTAFF') && !defined('GROUP') && !defined('CREATEGROUP');

    return $usersection ? 1 : 0;
}
Pat Kira's avatar
Pat Kira committed
124

125 126 127 128
/**
 * This function creates a Smarty object and sets it up for use within our
 * podclass app, setting up some variables.
 *
129 130
 * WARNING: If you are using pieforms, set them up BEFORE calling this function.
 *
131 132
 * The variables that it sets up are:
 *
133
 * - WWWROOT: The base url for the Mahara system
134 135 136 137 138
 * - 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).
139 140
 * - PUBLIC: Set true if this page is a public page
 * - MAINNAV: Array defining the main navigation
141
 *
142
 * @param $javascript A list of javascript includes.  Each include should be just
143
 *                    the name of a file, and reside in js/{filename}
144 145 146
 * @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.
147
 * @return Dwoo_Mahara
148
 */
149

150 151


152
function smarty($javascript = array(), $headers = array(), $pagestrings = array(), $extraconfig = array()) {
153
    global $USER, $SESSION, $THEME, $HEADDATA, $langselectform, $CFG, $viewid;
154 155 156 157 158 159 160 161 162 163 164

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

165
    $sideblocks = array();
166 167 168 169 170
    // Some things like die_info() will try and create a smarty() call when we are already in one, which causes
    // language_select_form() to throw headdata error as it is called twice.
    if (!isset($langselectform)) {
        $langselectform = language_select_form();
    }
171 172
    $smarty = smarty_core();

173
    $wwwroot = get_config('wwwroot');
Aaron Wells's avatar
Aaron Wells committed
174
    // NOTE: not using jswwwroot - it seems to wreck image paths if you
175
    // drag them around the wysiwyg editor
176
    $jswwwroot = json_encode($wwwroot);
Martyn Smith's avatar
Martyn Smith committed
177

178 179 180 181 182 183 184 185 186 187
    // Workaround for $cfg->cleanurlusersubdomains.
    // When cleanurlusersubdomains is on, ajax requests might come from somewhere other than
    // the wwwroot.  To avoid cross-domain requests, set a js variable when this page is on a
    // different subdomain, and let the ajax wrapper function sendjsonrequest rewrite its url
    // if necessary.
    if (get_config('cleanurls') && get_config('cleanurlusersubdomains')) {
        if ($requesthost = get_requested_host_name()) {
            $wwwrootparts = parse_url($wwwroot);
            if ($wwwrootparts['host'] != $requesthost) {
                $fakewwwroot = $wwwrootparts['scheme'] . '://' . $requesthost . '/';
188
                $headers[] = '<script type="application/javascript">var fakewwwroot = ' . json_encode($fakewwwroot) . ';</script>';
189 190 191 192
            }
        }
    }

Martyn Smith's avatar
Martyn Smith committed
193
    $theme_list = array();
194
    $adminsection = in_admin_section();
Aaron Wells's avatar
Aaron Wells committed
195

196 197
    if (function_exists('pieform_get_headdata')) {
        $headers = array_merge($headers, pieform_get_headdata());
198 199 200
        if (!defined('PIEFORM_GOT_HEADDATA')) {
          define('PIEFORM_GOT_HEADDATA', 1);
        }
201
    }
202

203 204 205
    // Define the stylesheets array early so that javascript modules can add extras
    $stylesheets = array();

Aaron Wells's avatar
Aaron Wells committed
206
    // Insert the appropriate javascript tags
207
    $javascript_array = array();
208
    $jsroot = $wwwroot . 'js/';
209

210 211
    $langdirection = get_string('thisdirection', 'langconfig');

212 213
    // Make jQuery accessible with $j (Mochikit has $)
    $javascript_array[] = $jsroot . 'jquery/jquery.js';
214
    $headers[] = '<script type="application/javascript">$j=jQuery;</script>';
215

216 217 218 219 220
    // If necessary, load MathJax configuration
    if (get_config('mathjax')) {
        $headers[] = '<script type="application/javascript">'.get_config('mathjaxconfig').'</script>';
    }

Richard Mansfield's avatar
Richard Mansfield committed
221
    // TinyMCE must be included first for some reason we're not sure about
222 223 224 225
    //
    // Note: we do not display tinyMCE for mobile devices
    // as it doesn't work on some of them and can
    // disable the editing of a textarea field
226
    if (is_html_editor_enabled()) {
227 228
        $checkarray = array(&$javascript, &$headers);
        $found_tinymce = false;
229 230 231 232 233 234 235 236 237
        $tinymceviewid = 'null';
        if ($inpersonalarea = user_personal_section()) {
            if (defined('SECTION_PAGE') && (SECTION_PAGE == 'view' || SECTION_PAGE == 'blocks' || SECTION_PAGE == 'editlayout')) {
                if (isset($viewid) && $viewid > 0) {
                    $tinymceviewid = $viewid;
                }
            }
        }

238 239 240 241
        foreach ($checkarray as &$check) {
            if (($key = array_search('tinymce', $check)) !== false || ($key = array_search('tinytinymce', $check)) !== false) {
                if (!$found_tinymce) {
                    $found_tinymce = $check[$key];
242
                    $javascript_array[] = $wwwroot . 'artefact/file/js/filebrowser.js';
243
                    $javascript_array[] = $jsroot . 'switchbox.js';
244 245
                    $javascript_array[] = $jsroot . 'tinymce/tinymce.js';
                    $stylesheets = array_merge($stylesheets, array_reverse(array_values($THEME->get_url('style/tinymceskin.css', true))));
246
                    $content_css = json_encode($THEME->get_url('style/tinymce.css'));
247 248
                    $language = current_language();
                    $language = substr($language, 0, ((substr_count($language, '_') > 0) ? 5 : 2));
249
                    if ($language != 'en' && !file_exists(get_config('docroot') . 'js/tinymce/langs/' . $language . '.js')) {
250 251 252 253 254 255 256 257
                        // In case the language file exists as a string with both lower and upper case, eg fr_FR we test for this
                        $language = substr($language, 0, 2) . '_' . strtoupper(substr($language, 0, 2));
                        if (!file_exists(get_config('docroot') . 'js/tinymce/langs/' . $language . '.js')) {
                            // In case we fail to find a language of 5 chars, eg pt_BR (Portugese, Brazil) we try the 'parent' pt (Portugese)
                            $language = substr($language, 0, 2);
                            if ($language != 'en' && !file_exists(get_config('docroot') . 'js/tinymce/langs/' . $language . '.js')) {
                                $language = 'en';
                            }
258
                        }
259 260
                    }
                    $extrasetup = isset($extraconfig['tinymcesetup']) ? $extraconfig['tinymcesetup'] : '';
261
                    $extramceconfig = isset($extraconfig['tinymceconfig']) ? $extraconfig['tinymceconfig'] : '';
262

263
                    // Check whether to make the spellchecker available
264
                    if (get_config('tinymcespellcheckerengine')) {
265
                        $spellchecker = ',spellchecker';
266
                        $spellchecker_toolbar = '| spellchecker';
267
                        $spellchecker_config = "gecko_spellcheck : false, spellchecker_rpc_url : \"{$jsroot}tinymce/plugins/spellchecker/spellchecker.php\",";
268 269
                    }
                    else {
270
                        $spellchecker = $spellchecker_toolbar = '';
271 272
                        $spellchecker_config = 'gecko_spellcheck : true,';
                    }
273 274
                    $mathslate = (get_config('mathjax')) ? 'mathslate' : '';
                    $mathslateplugin = !empty($mathslate) ? ',' . $mathslate : '';
275
                    $toolbar = array(
276
                        null,
277
                        '"toolbar_toggle | formatselect | bold italic | bullist numlist | link unlink | imagebrowser | undo redo"',
278
                        '"underline strikethrough subscript superscript | alignleft aligncenter alignright alignjustify | outdent indent | forecolor backcolor | ltr rtl | fullscreen"',
279
                        '"fontselect | fontsizeselect | emoticons nonbreaking charmap ' . $mathslate . ' ' . $spellchecker_toolbar . ' | table | removeformat pastetext | code"',
280 281 282 283 284 285
                    );

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

286 287 288 289
                    // Language strings required for TinyMCE
                    $pagestrings['mahara'] = isset($pagestrings['mahara']) ? $pagestrings['mahara'] : array();
                    $pagestrings['mahara'][] = 'attachedimage';

290 291 292 293 294 295 296 297 298 299 300
                    $tinymceinitbehatsetup = '';
                    $tinymcebehatsetup = '';
                    if (defined('BEHAT_TEST')) {
                        $tinymceinitbehatsetup = 'window.isEditorInitializing = false;';
                        $tinymcebehatsetup = <<<EOF
        ed.on('PreInit', function(ed) {
            window.isEditorInitializing = true;
        });
EOF;
                    }

301
                    if ($check[$key] == 'tinymce') {
302 303
                        $tinymceconfig = <<<EOF
    theme: "modern",
304
    plugins: "tooltoggle,textcolor,visualblocks,wordcount,link,lists,imagebrowser,table,emoticons{$spellchecker},paste,code,fullscreen,directionality,searchreplace,nonbreaking,charmap{$mathslateplugin}",
305
    skin: 'light',
306 307
    toolbar1: {$toolbar[1]},
    toolbar2: {$toolbar[2]},
308
    toolbar3: {$toolbar[3]},
309
    menubar: false,
310
    fix_list_elements: true,
311
    image_advtab: true,
312
    table_style_by_css: true,
313
    {$spellchecker_config}
314
EOF;
315 316
                    }
                    else {
317 318 319
                        $tinymceconfig = <<<EOF
    selector: "textarea.tinywysiwyg",
    theme: "modern",
320
    skin: 'light',
321 322
    plugins: "fullscreen,autoresize",
    toolbar: {$toolbar[0]},
323
EOF;
324
                    }
325

326
                    $headers[] = <<<EOF
327
<script type="application/javascript">
328
tinyMCE.init({
329 330
    {$tinymceconfig}
    schema: 'html4',
331 332 333 334 335 336 337 338
    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|name|scrolling|frameborder|allowfullscreen|webkitallowfullscreen|mozallowfullscreen|longdesc|marginheight|marginwidth|align|title|class|type]"
        + ",a[id|class|title|href|name]"
339
        + ",button[id|class|title]"
340
    ,urlconverter_callback : "custom_urlconvert",
341
    language: '{$language}',
342
    directionality: "{$tinymce_langdir}",
343
    content_css : {$content_css},
344
    font_formats: 'Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Open Sans=Open Sans;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats;',
345
    remove_script_host: false,
346
    relative_urls: false,
347
    target_list: false,
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
    link_list: function(success) {
        // Only show the list of links in the normal user section
        if ({$inpersonalarea}) {
            var params = {
                'viewid': {$tinymceviewid}
            }
            sendjsonrequest(config['wwwroot'] + 'json/tinymceviewlist.json.php',  params, 'POST', function(data) {
                if (data.count > 0) {
                    success(JSON.parse(data.data));
                }
                else {
                    success(''); // stop showing list with only option being 'none'
                }
            });
        }
        else {
            success(''); // stop showing list with only option being 'none'
        }
    },

Aaron Wells's avatar
Aaron Wells committed
368
    cache_suffix: '?v={$CFG->cacheversion}',
369
    {$extramceconfig}
370
    setup: function(ed) {
371
        {$tinymcebehatsetup}
372
        ed.on('init', function(ed) {
373
        {$tinymceinitbehatsetup}
374
            if (typeof(editor_to_focus) == 'string' && ed.editorId == editor_to_focus) {
375 376 377
                ed.focus();
            }
        });
378 379 380
        ed.on('keyup change', function (e) {
            checkTextareaMaxLength(ed.settings.id);
        });
381 382
        ed.on('LoadContent', function(e) {
            // Hide all the 2nd/3rd row menu buttons
383
            jQuery('.mce-toolbar.mce-first').siblings().addClass('hidden');
384 385 386 387 388 389 390 391 392 393 394
            // The tinymce fullscreen mode does not work properly in a transformed container div
            // such as div.vertcentre
            // and IE doesn't like a preset z-index
            // This work-around will remove/add classes: .vertcenter .configure .blockinstane
            // of the configure block div
            // when toggling fullscreen
            jQuery('div[aria-label="Fullscreen"]').on('click', function(e) {
                jQuery('div#configureblock').toggleClass('vertcentre');
                jQuery('div#configureblock').toggleClass('blockinstance');
                jQuery('div#configureblock').toggleClass('configure');
            });
395
        });
396
        {$extrasetup}
397
    }
398
});
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415

function imageBrowserConfigSuccess(form, data) {
    // handle updates to file browser
    // final form submission handled by tinymce plugin
    if (data.formelementsuccess) {
        eval(data.formelementsuccess + '(form, data)');
        return;
    }
}

function imageBrowserConfigError(form, data) {
    if (data.formelementerror) {
        eval(data.formelementerror + '(form, data)');
        return;
    }
}

416
function custom_urlconvert (u, n, e) {
417 418
    // Don't convert the url on the skype status buttons.
    if (u.indexOf('skype:') == 0) {
419
      return u;
420 421
    }
    var t = tinyMCE.activeEditor, s = t.settings;
422

423 424
    // 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)
425 426
      return u;

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

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

434
    return u;
435
}
436 437 438
</script>

EOF;
439 440 441 442 443 444 445
                    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]);
446
                }
447
            }
448

449 450 451 452
            // If any page adds jquery explicitly, remove it from the list
            if (($key = array_search('jquery', $check)) !== false) {
                unset($check[$key]);
            }
453
        }
454
    }
455 456 457 458 459 460 461 462
    else {
        if (($key = array_search('tinymce', $javascript)) !== false || ($key = array_search('tinytinymce', $javascript)) !== false) {
            unset($javascript[$key]);
        }
        if (($key = array_search('tinymce', $headers)) !== false || ($key = array_search('tinytinymce', $headers)) !== false) {
            unset($headers[$key]);
        }
    }
Martyn Smith's avatar
Martyn Smith committed
463
    $javascript_array[] = $jsroot . 'keyboardNavigation.js';
464

465 466 467 468 469
    //If necessary, load MathJax path
    if (get_config('mathjax')) {
        $javascript_array[] = get_config('mathjaxpath');
    }

470
    $strings = array();
471 472 473 474 475 476 477 478 479
    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);
        }
480 481
    }

482
    $jsstrings = jsstrings();
Martyn Smith's avatar
Martyn Smith committed
483
    $themepaths = themepaths();
484

Richard Mansfield's avatar
Richard Mansfield committed
485
    foreach ($javascript as $jsfile) {
486 487 488 489
        // 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.
490
        if (strpos($jsfile, '/') === false) {
491
            $javascript_array[] = $jsroot . $jsfile . '.js';
492
            if (isset($jsstrings[$jsfile])) {
493 494 495
                foreach ($jsstrings[$jsfile] as $section => $tags) {
                    foreach ($tags as $tag) {
                        $strings[$tag] = get_raw_string($tag, $section);
496 497 498
                    }
                }
            }
Martyn Smith's avatar
Martyn Smith committed
499 500
            if (isset($themepaths[$jsfile])) {
                foreach ($themepaths[$jsfile] as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
501
                    $theme_list[$themepath] = $THEME->get_url($themepath);
Martyn Smith's avatar
Martyn Smith committed
502 503
                }
            }
504
        }
505
        else if (stripos($jsfile, 'http://') === false && stripos($jsfile, 'https://') === false) {
506
            // A local .js file with a fully specified path
507
            $javascript_array[] = $wwwroot . $jsfile;
508 509 510 511 512 513
            // If $jsfile is from a plugin or plugin's block, i.e.:
            // - plugintype/pluginname/js/foo.js
            // - plugintype/pluginname/blocktype/pluginname/js/foo.js
            // Then get js strings from static function jsstrings in:
            // - plugintype/pluginname/lib.php, or
            // - plugintype/pluginname/blocktype/pluginname/lib.php
514
            $bits = explode('/', $jsfile);
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
            $pluginname = false;
            $plugintype = false;
            $jsfilename = false;
            if (count($bits) == 4 && $bits[2] == 'js' && in_array($bits[0], plugin_types())) {
                $plugintype = $bits[0];
                $pluginname = $bits[1];
                $jsfilename = $bits[3];
            }
            if (count($bits) == 6 && $bits[0] == 'artefact' && $bits[2] == 'blocktype' && $bits[4] == 'js') {
                $plugintype = 'blocktype';
                $pluginname = $bits[3];
                $jsfilename = $bits[5];
            }
            if ($pluginname) {
                safe_require($plugintype, $pluginname);
                $pluginclass = generate_class_name($plugintype, $pluginname);
                $name = substr($jsfilename, 0, strpos($jsfilename, '.js'));
532 533
                if (is_callable(array($pluginclass, 'jsstrings'))) {
                    $tempstrings = call_static_method($pluginclass, 'jsstrings', $name);
534 535 536
                    foreach ($tempstrings as $section => $tags) {
                        foreach ($tags as $tag) {
                            $strings[$tag] = get_raw_string($tag, $section);
537 538
                        }
                    }
Richard Mansfield's avatar
Richard Mansfield committed
539
                }
540 541 542 543
                if (is_callable(array($pluginclass, 'jshelp'))) {
                    $tempstrings = call_static_method($pluginclass, 'jshelp', $name);
                    foreach ($tempstrings as $section => $tags) {
                        foreach ($tags as $tag) {
544
                            $strings[$tag . '.help'] = get_help_icon($plugintype, $pluginname, null, null,
545 546 547 548
                                                                     null, $tag);
                        }
                    }
                }
Martyn Smith's avatar
Martyn Smith committed
549 550 551
                if (is_callable(array($pluginclass, 'themepaths'))) {
                    $tmpthemepaths = call_static_method($pluginclass, 'themepaths', $name);
                    foreach ($tmpthemepaths as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
552
                        $theme_list[$themepath] = $THEME->get_url($themepath);
Martyn Smith's avatar
Martyn Smith committed
553 554
                    }
                }
Martyn Smith's avatar
Martyn Smith committed
555
            }
Martyn Smith's avatar
Martyn Smith committed
556
        }
557 558 559 560
        else {
            // A remote .js file
            $javascript_array[] = $jsfile;
        }
561
    }
562 563

    $javascript_array[] = $jsroot . 'mahara.js';
564
    $javascript_array[] = $jsroot . 'formchangechecker.js';
565
    $javascript_array[] = $jsroot . 'textareamaxlengthchecker.js';
566

567 568 569 570 571 572
    // Load some event handler functions for checking if all AJAX requests have completed
    // when running behat tests
    if (defined('BEHAT_TEST')) {
        $javascript_array[] = get_config('wwwroot') . 'testing/frameworks/behat/page_status.js';
    }

573 574 575
    foreach ($jsstrings['mahara'] as $section => $tags) {
        foreach ($tags as $tag) {
            $strings[$tag] = get_raw_string($tag, $section);
576 577
        }
    }
578 579
    if (isset($extraconfig['themepaths']) && is_array($extraconfig['themepaths'])) {
        foreach ($extraconfig['themepaths'] as $themepath) {
Nigel McNie's avatar
Nigel McNie committed
580
            $theme_list[$themepath] = $THEME->get_url($themepath);
581 582
        }
    }
583

584
    $stringjs = '<script type="application/javascript">';
585
    $stringjs .= 'var strings = ' . json_encode($strings) . ';';
586
    $stringjs .= "\nfunction plural(n) { return " . get_raw_string('pluralrule', 'langconfig') . "; }\n";
587 588
    $stringjs .= '</script>';

589

590 591 592
    // Allow us to set the HTML lang attribute
    $smarty->assign('LANGUAGE', substr(current_language(), 0, 2));

593
    $smarty->assign('STRINGJS', $stringjs);
594

595
    $stylesheets = get_stylesheets_for_current_page($stylesheets, $extraconfig);
596

Son Nguyen's avatar
Son Nguyen committed
597 598 599 600
    // Disable CSS transforms, transitions, and animations when running behat tests
    if (defined('BEHAT_TEST')) {
        $stylesheets[] = get_config('wwwroot') . 'testing/frameworks/behat/no_transitions.css';
    }
601
    $smarty->assign('STYLESHEETLIST', $stylesheets);
602 603
    if (!empty($theme_list)) {
        // this gets assigned in smarty_core, but do it again here if it's changed locally
Aaron Wells's avatar
Aaron Wells committed
604
        $smarty->assign('THEMELIST', json_encode(array_merge((array)json_decode($smarty->get_template_vars('THEMELIST')),  $theme_list)));
605
    }
606

607 608 609 610 611
    $dropdownmenu = get_config('dropdownmenu');
    // disable drop-downs if overridden at institution level
    $sitethemeprefs = get_config('sitethemeprefs');
    $institutions = $USER->institutions;
    if (!empty($institutions)) {
612 613 614 615
        if (count($institutions) == 1) {
            $i = reset($institutions);
            if ($i->theme == $THEME->basename && $USER->institutiontheme->institutionname == $i->institution) {
                $dropdownmenu = $i->dropdownmenu;
616
            }
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
        }
        else {
            foreach ($institutions as $i) {
                if (!empty($sitethemeprefs)) {
                    if (!empty($USER->accountprefs['theme']) && $USER->accountprefs['theme'] == $THEME->basename . '/' . $i->institution) {
                        $dropdownmenu = $i->dropdownmenu;
                        break;
                    }
                }
                else {
                    if ((!empty($USER->accountprefs['theme']) && $USER->accountprefs['theme'] == $THEME->basename . '/' . $i->institution)
                        || (empty($USER->accountprefs) && $i->theme == $THEME->basename && $USER->institutiontheme->institutionname == $i->institution)) {
                        $dropdownmenu = $i->dropdownmenu;
                        break;
                    }
632 633 634 635 636 637
                }
            }
        }
    }

    // and/or disable drop-downs if a handheld device detected
638
    $dropdownmenu = $SESSION->get('handheld_device') ? false : $dropdownmenu && get_config('dropdownmenuenabled');
639

640 641
    if ($dropdownmenu) {
        $smarty->assign('DROPDOWNMENU', $dropdownmenu);
642
        $javascript_array[] = $jsroot . 'dropdown-nav.js';
643
    }
644

645
    $smarty->assign('MOBILE', $SESSION->get('mobile'));
646
    $smarty->assign('HANDHELD_DEVICE', $SESSION->get('handheld_device'));
647 648 649 650 651 652 653 654 655
    if (defined('FILEBROWSERS') ||
        (defined('SECTION_PAGE') && SECTION_PAGE == 'blocks')) {
        // Need to add the headers for select2 here so filebrowser has correct language
        require_once(get_config('libroot') . 'form/elements/autocomplete.php');
        $select2lang = pieform_element_autocomplete_language();
        $select2headdata = pieform_element_autocomplete_get_headdata();
        $headers = array_merge($headers, $select2headdata);
        $smarty->assign('select2_language', $select2lang);
    }
656

657 658 659 660
    $sitename = get_config('sitename');
    if (!$sitename) {
       $sitename = 'Mahara';
    }
661
    $smarty->assign('sitename', $sitename);
662

663 664 665 666
    $sitelogocustom = false;
    if (get_config('installed')) {
        $sitelogocustom = (int) (get_field('institution', 'logo', 'name', 'mahara') || $THEME->headerlogo);
    }
667
    $smarty->assign('sitelogocustom', $sitelogocustom);
668
    $sitelogo = $THEME->header_logo();
669
    $sitelogo = append_version_number($sitelogo);
670 671
    $sitelogosmall = $THEME->header_logo_small();
    $sitelogosmall = ($sitelogosmall ? append_version_number($sitelogosmall) : null);
672
    $smarty->assign('sitelogo', $sitelogo);
673
    $smarty->assign('sitelogosmall', $sitelogosmall);
674 675
    $smarty->assign('sitelogo4facebook', $THEME->facebook_logo());
    $smarty->assign('sitedescription4facebook', get_string('facebookdescription', 'mahara'));
676

Martyn Smith's avatar
Martyn Smith committed
677
    if (defined('TITLE')) {
678
        $smarty->assign('PAGETITLE', TITLE . ' - ' . $sitename);
Martyn Smith's avatar
Martyn Smith committed
679 680
    }
    else {
681
        $smarty->assign('PAGETITLE', $sitename);
Martyn Smith's avatar
Martyn Smith committed
682
    }
683 684 685 686 687 688 689 690 691
    if (defined('PAGEHEADING')) {
        $smarty->assign('PAGEHEADING', PAGEHEADING);
    }
    else {
        if (defined('TITLE')) {
            $smarty->assign('PAGEHEADING', TITLE);
        }
    }

692 693 694
    if (defined('SUBSECTIONHEADING')) {
        $smarty->assign('SUBSECTIONHEADING', SUBSECTIONHEADING);
    }
Martyn Smith's avatar
Martyn Smith committed
695

696
    $smarty->assign('PRODUCTIONMODE', get_config('productionmode'));
697
    if (function_exists('local_header_top_content')) {
698
        $sitetop = (isset($sitetop) ? $sitetop : '') . local_header_top_content();
699 700 701
    }
    if (isset($sitetop)) {
        $smarty->assign('SITETOP', $sitetop);
702
    }
703 704 705
    if (defined('PUBLIC')) {
        $smarty->assign('PUBLIC', true);
    }
706 707 708
    if (defined('ADMIN')) {
        $smarty->assign('ADMIN', true);
    }
709 710 711
    if (defined('INSTITUTIONALADMIN')) {
        $smarty->assign('INSTITUTIONALADMIN', true);
    }
712 713 714 715 716 717
    if (defined('STAFF')) {
        $smarty->assign('STAFF', true);
    }
    if (defined('INSTITUTIONALSTAFF')) {
        $smarty->assign('INSTITUTIONALSTAFF', true);
    }
718

719
    $smarty->assign('LOGGEDIN', $USER->is_logged_in());
720
    $smarty->assign('loggedout', !$USER->is_logged_in());
721 722 723 724 725 726 727
    $publicsearchallowed = false;
    $searchplugin = get_config('searchplugin');
    if ($searchplugin) {
        safe_require('search', $searchplugin);
        $publicsearchallowed = (call_static_method(generate_class_name('search', $searchplugin), 'publicform_allowed') && get_config('publicsearchallowed'));
    }
    $smarty->assign('publicsearchallowed', $publicsearchallowed);
728
    if ($USER->is_logged_in()) {
729
        global $SELECTEDSUBNAV; // It's evil, but rightnav & mainnav stuff are now in different templates.
730 731 732 733 734 735 736 737 738 739 740
        if (in_array('raw_old', $THEME->inheritance)) {
            $menutype = (in_admin_section() ? 'adminnav' : null);
            $smarty->assign('MAINNAV', main_nav($menutype));
        }
        else {
            $smarty->assign('MAINNAV', main_nav());
            $is_admin = $USER->get('admin') || $USER->is_institutional_admin() || $USER->get('staff') || $USER->is_institutional_staff();
            if ($is_admin) {
                $smarty->assign('MAINNAVADMIN', main_nav('adminnav'));
            }
        }
741
        $mainnavsubnav = $SELECTEDSUBNAV;
742
        $smarty->assign('RIGHTNAV', right_nav());
743 744 745 746 747 748 749 750 751
        if (!$mainnavsubnav && $dropdownmenu) {
            // In drop-down navigation, the submenu is only usable if its parent is one of the top-level menu
            // items.  But if the submenu comes from something in right_nav (settings), it's unreachable.
            // Turning the submenu into SUBPAGENAV group-style tabs makes it usable.
            $smarty->assign('SUBPAGENAV', $SELECTEDSUBNAV);
        }
        else {
            $smarty->assign('SELECTEDSUBNAV', $SELECTEDSUBNAV);
        }
752
    }
753
    else {
754
        $smarty->assign('languageform', $langselectform);
755
    }
756
    $smarty->assign('FOOTERMENU', footer_menu());
757

758
    $smarty->assign('USER', $USER);
759
    $smarty->assign('SESSKEY', $USER->get('sesskey'));
760
    $smarty->assign('CC_ENABLED', get_config('cookieconsent_enabled'));
761
    $javascript_array = append_version_number($javascript_array);
762
    $smarty->assign('JAVASCRIPT', $javascript_array);
763
    $smarty->assign('RELEASE', get_config('release'));
764
    $smarty->assign('SERIES', get_config('series'));
765
    $smarty->assign('CACHEVERSION', get_config('cacheversion', 0));
766
    if (get_config('siteclosedforupgrade')) {
767
        $smarty->assign('SITECLOSED', 'logindisabled');
768
    }
769
    else if (get_config('siteclosedbyadmin')) {
770
        $smarty->assign('SITECLOSED', 'loginallowed');
771
    }
772

773 774
    if ((!isset($extraconfig['pagehelp']) || $extraconfig['pagehelp'] !== false)
        and $help = has_page_help()) {
775 776 777
        $smarty->assign('PAGEHELPNAME', $help[0]);
        $smarty->assign('PAGEHELPICON', $help[1]);
    }
778
    if (defined('GROUP')) {
779
        require_once('group.php');
780 781 782 783 784 785
        if ($group = group_current_group()) {
            $smarty->assign('GROUP', $group);
            if (!defined('NOGROUPMENU')) {
                $smarty->assign('SUBPAGENAV', group_get_menu_tabs());
                $smarty->assign('PAGEHEADING', $group->name);
            }
786
        }
787
    }
788

Martyn Smith's avatar
Martyn Smith committed
789
    // ---------- sideblock stuff ----------
790 791
    $sidebars = !isset($extraconfig['sidebars']) || $extraconfig['sidebars'] !== false;
    if ($sidebars && !defined('INSTALLER') && (!defined('MENUITEM') || substr(MENUITEM, 0, 5) != 'admin')) {
792
        if (get_config('installed') && !$adminsection) {
793 794 795
            $data = site_menu();
            if (!empty($data)) {
                $smarty->assign('SITEMENU', site_menu());
796
                $sideblocks[] = array(
797
                    'name'   => 'linksandresources',
798 799 800 801 802 803
                    'weight' => 10,
                    'data'   => $data,
                );
            }
        }

804 805
        if ($USER->is_logged_in() && defined('MENUITEM') &&
            (substr(MENUITEM, 0, 11) == 'myportfolio' || substr(MENUITEM, 0, 7) == 'content')) {
806
            if (get_config('showselfsearchsideblock')) {
807
                $sideblocks[] = array(
808 809 810 811 812 813
                    'name'   => 'selfsearch',
                    'weight' => 0,
                    'data'   => array(),
                );
            }
            if (get_config('showtagssideblock')) {
814
                $sideblocks[] = array(
815 816 817 818 819 820
                    'name'   => 'tags',
                    'id'     => 'sb-tags',
                    'weight' => 0,
                    'data'   => tags_sideblock(),
                );
            }
Clare Lenihan's avatar
Clare Lenihan committed
821
        }
Clare Lenihan's avatar
Clare Lenihan committed
822

823
        if ($USER->is_logged_in() && !$adminsection) {
824
            $sideblocks[] = array(
825
                'name'   => 'profile',
826
                'id'     => 'sb-profile',
827
                'class' => 'user-panel',
828 829 830
                'weight' => -20,
                'data'   => profile_sideblock()
            );
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845
            $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) {
846
                $sideblocks[] = array(
847
                    'name'   => 'onlineusers',
848
                    'id'     => 'sb-onlineusers',
849 850 851 852
                    'weight' => -10,
                    'data'   => onlineusers_sideblock(),
                );
            }
853
            if (get_config('showprogressbar') && $USER->get_account_preference('showprogressbar')) {
854
                $sideblocks[] = array(
855 856
                    'name'   => 'progressbar',
                    'id'     => 'sb-progressbar',
857
                    'class'  => 'progressbar',
858
                    'weight' => -8,
859 860 861 862 863 864
                    'data'   => progressbar_sideblock(),
                );
            }
        }

        if ($USER->is_logged_in() && $adminsection && defined('SECTION_PAGE') && SECTION_PAGE == 'progressbar') {
865
            $sideblocks[] = array(
866 867
                'name'   => 'progressbar',
                'id'     => 'sb-progressbar',
868
                'class'  => 'progressbar',
869
                'weight' => -8,
870 871
                'data'   => progressbar_sideblock(true),
            );
872
        }
Martyn Smith's avatar
Martyn Smith committed
873

874
        $isloginblockvisible = !$USER->is_logged_in() && !get_config('siteclosedforupgrade')
875 876
                && get_config('showloginsideblock');
        if ($isloginblockvisible) {
877
            $sideblocks[] = array(
878 879
                'name'   => 'login',
                'weight' => -10,
880
                'id'     => 'sb-loginbox',
881 882 883
                'data'   => array(
                    'loginform' => auth_generate_login_form(),
                ),
884 885
            );
        }
886
        $smarty->assign('SHOWLOGINBLOCK', $isloginblockvisible);
887

888 889 890
        if (get_config('enablenetworking')) {
            require_once(get_config('docroot') .'api/xmlrpc/lib.php');
            if ($USER->is_logged_in() && $ssopeers = get_service_providers($USER->authinstance)) {
891
                $sideblocks[] = array(
892 893 894 895 896
                    'name'   => 'ssopeers',
                    'weight' => 1,
                    'data'   => $ssopeers,
                );
            }
Martyn Smith's avatar
Martyn Smith committed
897 898
        }

899 900
        if (isset($extraconfig['sideblocks']) && is_array($extraconfig['sideblocks'])) {
            foreach ($extraconfig['sideblocks'] as $sideblock) {
901
                $sideblocks[] = $sideblock;
902 903
            }
        }
Martyn Smith's avatar
Martyn Smith committed
904

905
        // local_sideblocks_update allows sites to customise the sideblocks by munging the $sideblocks array.
9