Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merged changes for MDL-25394

  • Loading branch information...
commit 7bff5441c8b5f3d45edd4989cd03499a9594b983 2 parents 9bf5d89 + e5824bb
Sam Hemelryk samhemelryk authored
2  admin/settings/appearance.php
@@ -18,6 +18,8 @@
18 18 $temp->add(new admin_setting_configcheckbox('allowuserblockhiding', get_string('allowuserblockhiding', 'admin'), get_string('configallowuserblockhiding', 'admin'), 1));
19 19 $temp->add(new admin_setting_configcheckbox('allowblockstodock', get_string('allowblockstodock', 'admin'), get_string('configallowblockstodock', 'admin'), 1));
20 20 $temp->add(new admin_setting_configtextarea('custommenuitems', get_string('custommenuitems', 'admin'), get_string('configcustommenuitems', 'admin'), '', PARAM_TEXT, '50', '10'));
  21 + $temp->add(new admin_setting_configcheckbox('enabledevicedetection', get_string('enabledevicedetection', 'admin'), get_string('configenabledevicedetection', 'admin'), 1));
  22 + $temp->add(new admin_setting_devicedetectregex('devicedetectregex', get_string('devicedetectregex', 'admin'), get_string('devicedetectregex_desc', 'admin'), ''));
21 23 $ADMIN->add('themes', $temp);
22 24 $ADMIN->add('themes', new admin_externalpage('themeselector', get_string('themeselector','admin'), $CFG->wwwroot . '/theme/index.php'));
23 25
10 lang/en/admin.php
@@ -187,6 +187,7 @@
187 187 $string['configdeleteincompleteusers'] = 'After this period, old not fully setup accounts are deleted.';
188 188 $string['configdeleteunconfirmed'] = 'If you are using email authentication, this is the period within which a response will be accepted from users. After this period, old unconfirmed accounts are deleted.';
189 189 $string['configdenyemailaddresses'] = 'To deny email addresses from particular domains list them here in the same way. All other domains will be accepted. To deny subdomains add the domain with a preceding \'.\'. eg <strong>hotmail.com yahoo.co.uk .live.com</strong>';
  190 +$string['configenabledevicedetection'] = 'Enables detection of mobiles, smartphones, tablets or default devices (desktop PCs, laptops, etc) for the application of themes and other features.';
190 191 $string['configdigestmailtime'] = 'People who choose to have emails sent to them in digest form will be emailed the digest daily. This setting controls which time of day the daily mail will be sent (the next cron that runs after this hour will send it).';
191 192 $string['configdisableuserimages'] = 'Disable the ability for users to change user profile images.';
192 193 $string['configdisplayloginfailures'] = 'This will display information to selected users about previous failed logins.';
@@ -450,6 +451,12 @@
450 451 $string['density'] = 'Density';
451 452 $string['denyemailaddresses'] = 'Denied email domains';
452 453 $string['development'] = 'Development';
  454 +$string['devicedetectregex'] = 'Device detection regular expressions';
  455 +$string['devicedetectregex_desc'] = '<p>By default, Moodle can detect devices of the type default (desktop PCs, laptops, etc), mobile (phones and small hand held devices), tablet (iPads, Android tablets) and legacy (Internet Explorer 6 users). The theme selector can be used to apply separate themes to all of these. This setting allows regular expressions that allow the detection of extra device types (these take precedence over the default types).</p>
  456 +<p>For example, you could enter the regular expression \'/(MIDP-1.0|Maemo|Windows CE)/\' to detect some commonly used feasture phones add the return value \'featurephone\'. This adds \'featurephone\' on the theme selector that would allow you to add a theme that would be used on these devices. Other phones would still use the theme selected for the mobile device type.</p>';
  457 +$string['devicedetectregexexpression'] = 'Regular expression';
  458 +$string['devicedetectregexvalue'] = 'Return value';
  459 +$string['devicetype'] = 'Device type';
453 460 $string['digestmailtime'] = 'Hour to send digest emails';
454 461 $string['disableuserimages'] = 'Disable user profile images';
455 462 $string['displayerrorswarning'] = 'Enabling the PHP setting <em>display_errors</em> is not recommended on production sites because some error messages may reveal sensitive information about your server.';
@@ -491,6 +498,7 @@
491 498 $string['enablecourseajax'] = 'Enable AJAX course editing';
492 499 $string['enablecourseajax_desc'] = 'Allow AJAX when editing main course pages. Note that the course format and the theme must support AJAX editing and the user has to enable AJAX in their profiles, too.';
493 500 $string['enablecourserequests'] = 'Enable course requests';
  501 +$string['enabledevicedetection'] = 'Enable device detection';
494 502 $string['enableglobalsearch'] = 'Enable global search';
495 503 $string['enablegroupmembersonly'] = 'Enable group members only';
496 504 $string['enablehtmlpurifier'] = 'Enable HTML Purifier';
@@ -993,7 +1001,9 @@
993 1001 $string['tabselectedtofronttext'] = 'Bring selected tab row to front';
994 1002 $string['themedesignermode'] = 'Theme designer mode';
995 1003 $string['themelist'] = 'Theme list';
  1004 +$string['themenoselected'] = 'No theme selected';
996 1005 $string['themeresetcaches'] = 'Clear theme caches';
  1006 +$string['themeselect'] = 'Select theme';
997 1007 $string['themeselector'] = 'Theme selector';
998 1008 $string['themesettings'] = 'Theme settings';
999 1009 $string['therewereerrors'] = 'There were errors in your data';
1  lang/en/error.php
@@ -277,6 +277,7 @@
277 277 $string['invalidcoursenameshort'] = 'Invalid short course name';
278 278 $string['invaliddata'] = 'Data submitted is invalid';
279 279 $string['invaliddatarootpermissions'] = 'Invalid permissions detected in $CFG->dataroot directory, administrator has to fix permissions.';
  280 +$string['invaliddevicetype'] = 'Invalid device type';
280 281 $string['invalidelementid'] = 'Incorrect element id!';
281 282 $string['invalidentry'] = 'This is not valid entry!';
282 283 $string['invalidevent'] = 'Invalid event';
6 lang/en/moodle.php
@@ -906,7 +906,6 @@
906 906 $string['layouttable'] = 'Layout table';
907 907 $string['leavetokeep'] = 'Leave blank to keep current password';
908 908 $string['legacythemeinuse'] = 'This site is being displayed to you in compatibility mode because your browser is too old.';
909   -$string['legacythemesaved'] = 'New legacy theme saved';
910 909 $string['license'] = 'Licence';
911 910 $string['licenses'] = 'Licences';
912 911 $string['liketologin'] = 'Would you like to log in now with a full user account?';
@@ -1603,6 +1602,8 @@
1603 1602 $string['summary_help'] = 'The idea of a summary is a short text to prepare students for the activities within the topic or week. The text is shown on the course page under the section name.';
1604 1603 $string['summaryof'] = 'Summary of {$a}';
1605 1604 $string['supplyinfo'] = 'More details';
  1605 +$string['switchdevicedefault'] = 'Switch to the standard theme';
  1606 +$string['switchdevicerecommended'] = 'Switch to the recommended theme for your device';
1606 1607 $string['switchrolereturn'] = 'Return to my normal role';
1607 1608 $string['switchroleto'] = 'Switch role to...';
1608 1609 $string['tag'] = 'Tag';
@@ -1692,8 +1693,6 @@
1692 1693 $string['url'] = 'URL';
1693 1694 $string['used'] = 'Used';
1694 1695 $string['usedinnplaces'] = 'Used in {$a} places';
1695   -$string['useformaintheme'] = 'Use for modern browsers';
1696   -$string['useforlegacytheme'] = 'Use for old browsers';
1697 1696 $string['usemessageform'] = 'or use the form below to send a message to the selected students';
1698 1697 $string['user'] = 'User';
1699 1698 $string['userconfirmed'] = 'Confirmed {$a}';
@@ -1723,6 +1722,7 @@
1723 1722 $string['useruploadtype'] = 'User upload type: {$a}';
1724 1723 $string['userviewingsettings'] = 'Profile settings for {$a}';
1725 1724 $string['userzones'] = 'User zones';
  1725 +$string['usetheme'] = 'Use theme';
1726 1726 $string['usingexistingcourse'] = 'Using existing course';
1727 1727 $string['valuealreadyused'] = 'This value has already been used.';
1728 1728 $string['version'] = 'Version';
192 lib/adminlib.php
@@ -7335,9 +7335,199 @@ public function output_html($data, $query = '') {
7335 7335 $content .= html_writer::end_tag('div');
7336 7336 return format_admin_setting($this, $this->visiblename, $content, $this->description, false, '', $this->get_defaultsetting(), $query);
7337 7337 }
7338   -
7339 7338 }
7340 7339
  7340 +/**
  7341 + * Administration interface for user specified regular expressions for device detection.
  7342 + *
  7343 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  7344 + */
  7345 +class admin_setting_devicedetectregex extends admin_setting {
  7346 +
  7347 + /**
  7348 + * Calls parent::__construct with specific args
  7349 + *
  7350 + * @param string $name
  7351 + * @param string $visiblename
  7352 + * @param string $description
  7353 + * @param mixed $defaultsetting
  7354 + */
  7355 + public function __construct($name, $visiblename, $description, $defaultsetting = '') {
  7356 + global $CFG;
  7357 + parent::__construct($name, $visiblename, $description, $defaultsetting);
  7358 + }
  7359 +
  7360 + /**
  7361 + * Return the current setting(s)
  7362 + *
  7363 + * @return array Current settings array
  7364 + */
  7365 + public function get_setting() {
  7366 + global $CFG;
  7367 +
  7368 + $config = $this->config_read($this->name);
  7369 + if (is_null($config)) {
  7370 + return null;
  7371 + }
  7372 +
  7373 + return $this->prepare_form_data($config);
  7374 + }
  7375 +
  7376 + /**
  7377 + * Save selected settings
  7378 + *
  7379 + * @param array $data Array of settings to save
  7380 + * @return bool
  7381 + */
  7382 + public function write_setting($data) {
  7383 + if (empty($data)) {
  7384 + $data = array();
  7385 + }
  7386 +
  7387 + if ($this->config_write($this->name, $this->process_form_data($data))) {
  7388 + return ''; // success
  7389 + } else {
  7390 + return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br');
  7391 + }
  7392 + }
  7393 +
  7394 + /**
  7395 + * Return XHTML field(s) for regexes
  7396 + *
  7397 + * @param array $data Array of options to set in HTML
  7398 + * @return string XHTML string for the fields and wrapping div(s)
  7399 + */
  7400 + public function output_html($data, $query='') {
  7401 + global $OUTPUT;
  7402 +
  7403 + $out = html_writer::start_tag('table', array('border' => 1, 'class' => 'generaltable'));
  7404 + $out .= html_writer::start_tag('thead');
  7405 + $out .= html_writer::start_tag('tr');
  7406 + $out .= html_writer::tag('th', get_string('devicedetectregexexpression', 'admin'));
  7407 + $out .= html_writer::tag('th', get_string('devicedetectregexvalue', 'admin'));
  7408 + $out .= html_writer::end_tag('tr');
  7409 + $out .= html_writer::end_tag('thead');
  7410 + $out .= html_writer::start_tag('tbody');
  7411 +
  7412 + if (empty($data)) {
  7413 + $looplimit = 1;
  7414 + } else {
  7415 + $looplimit = (count($data)/2)+1;
  7416 + }
  7417 +
  7418 + for ($i=0; $i<$looplimit; $i++) {
  7419 + $out .= html_writer::start_tag('tr');
  7420 +
  7421 + $expressionname = 'expression'.$i;
  7422 +
  7423 + if (!empty($data[$expressionname])){
  7424 + $expression = $data[$expressionname];
  7425 + } else {
  7426 + $expression = '';
  7427 + }
  7428 +
  7429 + $out .= html_writer::tag('td',
  7430 + html_writer::empty_tag('input',
  7431 + array(
  7432 + 'type' => 'text',
  7433 + 'class' => 'form-text',
  7434 + 'name' => $this->get_full_name().'[expression'.$i.']',
  7435 + 'value' => $expression,
  7436 + )
  7437 + ), array('class' => 'c'.$i)
  7438 + );
  7439 +
  7440 + $valuename = 'value'.$i;
  7441 +
  7442 + if (!empty($data[$valuename])){
  7443 + $value = $data[$valuename];
  7444 + } else {
  7445 + $value= '';
  7446 + }
  7447 +
  7448 + $out .= html_writer::tag('td',
  7449 + html_writer::empty_tag('input',
  7450 + array(
  7451 + 'type' => 'text',
  7452 + 'class' => 'form-text',
  7453 + 'name' => $this->get_full_name().'[value'.$i.']',
  7454 + 'value' => $value,
  7455 + )
  7456 + ), array('class' => 'c'.$i)
  7457 + );
  7458 +
  7459 + $out .= html_writer::end_tag('tr');
  7460 + }
  7461 +
  7462 + $out .= html_writer::end_tag('tbody');
  7463 + $out .= html_writer::end_tag('table');
  7464 +
  7465 + return format_admin_setting($this, $this->visiblename, $out, $this->description, false, '', null, $query);
  7466 + }
  7467 +
  7468 + /**
  7469 + * Converts the string of regexes
  7470 + *
  7471 + * @see self::process_form_data()
  7472 + * @param $regexes string of regexes
  7473 + * @return array of form fields and their values
  7474 + */
  7475 + protected function prepare_form_data($regexes) {
  7476 +
  7477 + $regexes = json_decode($regexes);
  7478 +
  7479 + $form = array();
  7480 +
  7481 + $i = 0;
  7482 +
  7483 + foreach ($regexes as $value => $regex) {
  7484 + $expressionname = 'expression'.$i;
  7485 + $valuename = 'value'.$i;
  7486 +
  7487 + $form[$expressionname] = $regex;
  7488 + $form[$valuename] = $value;
  7489 + $i++;
  7490 + }
  7491 +
  7492 + return $form;
  7493 + }
  7494 +
  7495 + /**
  7496 + * Converts the data from admin settings form into a string of regexes
  7497 + *
  7498 + * @see self::prepare_form_data()
  7499 + * @param array $data array of admin form fields and values
  7500 + * @return false|string of regexes
  7501 + */
  7502 + protected function process_form_data(array $form) {
  7503 +
  7504 + $count = count($form); // number of form field values
  7505 +
  7506 + if ($count % 2) {
  7507 + // we must get five fields per expression
  7508 + return false;
  7509 + }
  7510 +
  7511 + $regexes = array();
  7512 + for ($i = 0; $i < $count / 2; $i++) {
  7513 + $expressionname = "expression".$i;
  7514 + $valuename = "value".$i;
  7515 +
  7516 + $expression = trim($form['expression'.$i]);
  7517 + $value = trim($form['value'.$i]);
  7518 +
  7519 + if (empty($expression)){
  7520 + continue;
  7521 + }
  7522 +
  7523 + $regexes[$value] = $expression;
  7524 + }
  7525 +
  7526 + $regexes = json_encode($regexes);
  7527 +
  7528 + return $regexes;
  7529 + }
  7530 +}
7341 7531
7342 7532 /**
7343 7533 * Multiselect for current modules
2  lib/db/upgrade.php
@@ -6521,4 +6521,4 @@ function xmldb_main_upgrade($oldversion) {
6521 6521 // 1/ drop block_pinned_old table here and in install.xml
6522 6522 // 2/ drop block_instance_old table here and in install.xml
6523 6523
6524   -//TODO: AFTER 2.0 remove the column user->emailstop and the user preference "message_showmessagewindow"
  6524 +//TODO: AFTER 2.0 remove the column user->emailstop and the user preference "message_showmessagewindow"
137 lib/moodlelib.php
@@ -7605,6 +7605,143 @@ function check_browser_version($brand, $version = null) {
7605 7605 }
7606 7606
7607 7607 /**
  7608 + * Returns whether a device/browser combination is mobile, tablet, legacy, default or the result of
  7609 + * an optional admin specified regular expression. If enabledevicedetection is set to no or not set
  7610 + * it returns default
  7611 + *
  7612 + * @return string device type
  7613 + */
  7614 +function get_device_type() {
  7615 + global $CFG;
  7616 +
  7617 + if (empty($CFG->enabledevicedetection) || empty($_SERVER['HTTP_USER_AGENT'])) {
  7618 + return 'default';
  7619 + }
  7620 +
  7621 + $useragent = $_SERVER['HTTP_USER_AGENT'];
  7622 +
  7623 + if (!empty($CFG->devicedetectregex)) {
  7624 + $regexes = json_decode($CFG->devicedetectregex);
  7625 +
  7626 + foreach ($regexes as $value=>$regex) {
  7627 + if (preg_match($regex, $useragent)) {
  7628 + return $value;
  7629 + }
  7630 + }
  7631 + }
  7632 +
  7633 + //mobile detection PHP direct copy from open source detectmobilebrowser.com
  7634 + $phonesregex = '/android|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i';
  7635 + $modelsregex = '/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i';
  7636 + if (preg_match($phonesregex,$useragent) || preg_match($modelsregex,substr($useragent, 0, 4))){
  7637 + return 'mobile';
  7638 + }
  7639 +
  7640 + $tabletregex = '/Tablet browser|iPad|iProd|GT-P1000|GT-I9000|SHW-M180S|SGH-T849|SCH-I800|Build\/ERE27|sholest/i';
  7641 + if (preg_match($tabletregex, $useragent)) {
  7642 + return 'tablet';
  7643 + }
  7644 +
  7645 + if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 6.') !== false) {
  7646 + return 'legacy';
  7647 + }
  7648 +
  7649 + return 'default';
  7650 +}
  7651 +
  7652 +/**
  7653 + * Returns a list of the device types supporting by Moodle
  7654 + *
  7655 + * @param boolean $incusertypes includes types specified using the devicedetectregex admin setting
  7656 + * @return array $types
  7657 + */
  7658 +function get_device_type_list($incusertypes = true) {
  7659 + global $CFG;
  7660 +
  7661 + $types = array('default', 'legacy', 'mobile', 'tablet');
  7662 +
  7663 + if ($incusertypes && !empty($CFG->devicedetectregex)) {
  7664 + $regexes = json_decode($CFG->devicedetectregex);
  7665 +
  7666 + foreach ($regexes as $value => $regex) {
  7667 + $types[] = $value;
  7668 + }
  7669 + }
  7670 +
  7671 + return $types;
  7672 +}
  7673 +
  7674 +/**
  7675 + * Returns the theme selected for a particular device or false if none selected.
  7676 + *
  7677 + * @param string $devicetype
  7678 + * @return string|false The name of the theme to use for the device or the false if not set
  7679 + */
  7680 +function get_selected_theme_for_device_type($devicetype = null) {
  7681 + global $CFG;
  7682 +
  7683 + if (empty($devicetype)) {
  7684 + $devicetype = get_user_device_type();
  7685 + }
  7686 +
  7687 + $themevarname = get_device_cfg_var_name($devicetype);
  7688 + if (empty($CFG->$themevarname)) {
  7689 + return false;
  7690 + }
  7691 +
  7692 + return $CFG->$themevarname;
  7693 +}
  7694 +
  7695 +/**
  7696 + * Returns the name of the device type theme var in $CFG (because there is not a standard convention to allow backwards compatability
  7697 + *
  7698 + * @param string $devicetype
  7699 + * @return string The config variable to use to determine the theme
  7700 + */
  7701 +function get_device_cfg_var_name($devicetype = null) {
  7702 + if ($devicetype == 'default' || empty($devicetype)) {
  7703 + return 'theme';
  7704 + }
  7705 +
  7706 + return 'theme' . $devicetype;
  7707 +}
  7708 +
  7709 +/**
  7710 + * Allows the user to switch the device they are seeing the theme for.
  7711 + * This allows mobile users to switch back to the default theme, or theme for any other device.
  7712 + *
  7713 + * @param string $newdevice The device the user is currently using.
  7714 + * @return string The device the user has switched to
  7715 + */
  7716 +function set_user_device_type($newdevice) {
  7717 + global $USER;
  7718 +
  7719 + $devicetype = get_device_type();
  7720 + $devicetypes = get_device_type_list();
  7721 +
  7722 + if ($newdevice == $devicetype) {
  7723 + unset_user_preference('switchdevice'.$devicetype);
  7724 + } else if (in_array($newdevice, $devicetypes)) {
  7725 + set_user_preference('switchdevice'.$devicetype, $newdevice);
  7726 + }
  7727 +}
  7728 +
  7729 +/**
  7730 + * Returns the device the user is currently using, or if the user has chosen to switch devices
  7731 + * for the current device type the type they have switched to.
  7732 + *
  7733 + * @return string The device the user is currently using or wishes to use
  7734 + */
  7735 +function get_user_device_type() {
  7736 + $device = get_device_type();
  7737 + $switched = get_user_preferences('switchdevice'.$device, false);
  7738 + if ($switched != false) {
  7739 + return $switched;
  7740 + }
  7741 + return $device;
  7742 +}
  7743 +
  7744 +/**
7608 7745 * Returns one or several CSS class names that match the user's browser. These can be put
7609 7746 * in the body tag of the page to apply browser-specific rules without relying on CSS hacks
7610 7747 *
40 lib/outputrenderers.php
@@ -362,10 +362,14 @@ public function standard_footer_html() {
362 362 // but some of the content won't be known until later, so we return a placeholder
363 363 // for now. This will be replaced with the real content in {@link footer()}.
364 364 $output = self::PERFORMANCE_INFO_TOKEN;
365   - if ($this->page->legacythemeinuse) {
  365 + if ($this->page->devicetypeinuse == 'legacy') {
366 366 // The legacy theme is in use print the notification
367 367 $output .= html_writer::tag('div', get_string('legacythemeinuse'), array('class'=>'legacythemeinuse'));
368 368 }
  369 +
  370 + // Get links to switch device types (only shown for users not on a default device)
  371 + $output .= $this->theme_switch_links();
  372 +
369 373 if (!empty($CFG->debugpageinfo)) {
370 374 $output .= '<div class="performanceinfo pageinfo">This page is: ' . $this->page->debug_summary() . '</div>';
371 375 }
@@ -2496,8 +2500,40 @@ protected function render_custom_menu_item(custom_menu_item $menunode) {
2496 2500 // Return the sub menu
2497 2501 return $content;
2498 2502 }
2499   -}
2500 2503
  2504 + /**
  2505 + * Renders theme links for switching between default and other themes.
  2506 + *
  2507 + * @return string
  2508 + */
  2509 + protected function theme_switch_links() {
  2510 +
  2511 + $actualdevice = get_device_type();
  2512 + $currentdevice = $this->page->devicetypeinuse;
  2513 + $switched = ($actualdevice != $currentdevice);
  2514 +
  2515 + if (!$switched && $currentdevice == 'default' && $actualdevice == 'default') {
  2516 + // The user is using the a default device and hasn't switched so don't shown the switch
  2517 + // device links.
  2518 + return '';
  2519 + }
  2520 +
  2521 + if ($switched) {
  2522 + $linktext = get_string('switchdevicerecommended');
  2523 + $devicetype = $actualdevice;
  2524 + } else {
  2525 + $linktext = get_string('switchdevicedefault');
  2526 + $devicetype = 'default';
  2527 + }
  2528 + $linkurl = new moodle_url('/theme/switchdevice.php', array('url' => $this->page->url, 'device' => $devicetype, 'sesskey' => sesskey()));
  2529 +
  2530 + $content = html_writer::start_tag('div', array('id' => 'theme_switch_link'));
  2531 + $content .= html_writer::link($linkurl, $linktext);
  2532 + $content .= html_writer::end_tag('div');
  2533 +
  2534 + return $content;
  2535 + }
  2536 +}
2501 2537
2502 2538 /// RENDERERS
2503 2539
73 lib/pagelib.php
@@ -64,13 +64,13 @@
64 64 * @property-read object $course The current course that we are inside - a row from the
65 65 * course table. (Also available as $COURSE global.) If we are not inside
66 66 * an actual course, this will be the site course.
  67 + * @property-read string $devicetypeinuse The name of the device type in use
67 68 * @property-read string $docspath The path to the Moodle docs for this page.
68 69 * @property-read string $focuscontrol The id of the HTML element to be focused when the page has loaded.
69 70 * @property-read bool $headerprinted
70 71 * @property-read string $heading The main heading that should be displayed at the top of the <body>.
71 72 * @property-read string $headingmenu The menu (or actions) to display in the heading
72 73 * @property-read array $layout_options Returns arrays with options for layout file.
73   - * @property-read bool $legacythemeinuse Returns true if the legacy theme is being used.
74 74 * @property-read navbar $navbar Returns the navbar object used to display the navbar
75 75 * @property-read global_navigation $navigation Returns the global navigation structure
76 76 * @property-read xml_container_stack $opencontainers Tracks XHTML tags on this page that have been opened but not closed.
@@ -217,10 +217,12 @@ class moodle_page {
217 217 protected $_legacybrowsers = array('MSIE' => 6.0);
218 218
219 219 /**
220   - * Is set to true if the chosen legacy theme is in use. False by default.
221   - * @var bool
  220 + * Is set to the name of the device type in use.
  221 + * This will we worked out when it is first used.
  222 + *
  223 + * @var string
222 224 */
223   - protected $_legacythemeinuse = false;
  225 + protected $_devicetypeinuse = null;
224 226
225 227 protected $_https_login_required = false;
226 228
@@ -523,11 +525,25 @@ protected function magic_get_theme() {
523 525 }
524 526
525 527 /**
  528 + * Please do not call this method directly, use the ->devicetypeinuse syntax. {@link __get()}.
  529 + *
  530 + * @return string The device type being used.
  531 + */
  532 + protected function magic_get_devicetypeinuse() {
  533 + if (empty($this->_devicetypeinuse)) {
  534 + $this->_devicetypeinuse = get_user_device_type();
  535 + }
  536 + return $this->_devicetypeinuse;
  537 + }
  538 +
  539 + /**
526 540 * Please do not call this method directly, use the ->legacythemeinuse syntax. {@link __get()}.
  541 + * @deprecated since 2.1
527 542 * @return bool
528 543 */
529 544 protected function magic_get_legacythemeinuse() {
530   - return ($this->_legacythemeinuse);
  545 + debugging('$PAGE->legacythemeinuse is a deprecated property - please use $PAGE->devicetypeinuse and check if it is equal to legacy.', DEVELOPER_DEBUG);
  546 + return ($this->devicetypeinuse == 'legacy');
531 547 }
532 548
533 549 /**
@@ -1280,16 +1296,15 @@ protected function resolve_theme() {
1280 1296 }
1281 1297 }
1282 1298
1283   - $theme = '';
1284 1299 foreach ($themeorder as $themetype) {
1285 1300 switch ($themetype) {
1286 1301 case 'course':
1287   - if (!empty($CFG->allowcoursethemes) and !empty($this->course->theme)) {
1288   - return $this->course->theme;
  1302 + if (!empty($CFG->allowcoursethemes) && !empty($this->_course->theme) && $this->devicetypeinuse == 'default') {
  1303 + return $this->_course->theme;
1289 1304 }
1290 1305
1291 1306 case 'category':
1292   - if (!empty($CFG->allowcategorythemes)) {
  1307 + if (!empty($CFG->allowcategorythemes) && $this->devicetypeinuse == 'default') {
1293 1308 $categories = $this->categories;
1294 1309 foreach ($categories as $category) {
1295 1310 if (!empty($category->theme)) {
@@ -1304,7 +1319,7 @@ protected function resolve_theme() {
1304 1319 }
1305 1320
1306 1321 case 'user':
1307   - if (!empty($CFG->allowuserthemes) and !empty($USER->theme)) {
  1322 + if (!empty($CFG->allowuserthemes) && !empty($USER->theme) && $this->devicetypeinuse == 'default') {
1308 1323 if ($mnetpeertheme) {
1309 1324 return $mnetpeertheme;
1310 1325 } else {
@@ -1315,33 +1330,23 @@ protected function resolve_theme() {
1315 1330 case 'site':
1316 1331 if ($mnetpeertheme) {
1317 1332 return $mnetpeertheme;
1318   - } else if(!empty($CFG->themelegacy) && $this->browser_is_outdated()) {
1319   - $this->_legacythemeinuse = true;
1320   - return $CFG->themelegacy;
1321   - } else {
1322   - return $CFG->theme;
1323 1333 }
  1334 + // First try for the device the user is using.
  1335 + $devicetheme = get_selected_theme_for_device_type($this->devicetypeinuse);
  1336 + if (!empty($devicetheme)) {
  1337 + return $devicetheme;
  1338 + }
  1339 + // Next try for the default device (as a fallback)
  1340 + $devicetheme = get_selected_theme_for_device_type('default');
  1341 + if (!empty($devicetheme)) {
  1342 + return $devicetheme;
  1343 + }
  1344 + // The default device theme isn't set up - use the overall default theme.
  1345 + return theme_config::DEFAULT_THEME;
1324 1346 }
1325 1347 }
1326 1348 }
1327 1349
1328   - /**
1329   - * Determines whether the current browser should
1330   - * default to the admin-selected legacy theme
1331   - *
1332   - * @return true if legacy theme should be used, otherwise false
1333   - *
1334   - */
1335   - protected function browser_is_outdated() {
1336   - foreach($this->_legacybrowsers as $browser => $version) {
1337   - // Check the browser is valid first then that its version is suitable
1338   - if(check_browser_version($browser, '0') &&
1339   - !check_browser_version($browser, $version)) {
1340   - return true;
1341   - }
1342   - }
1343   - return false;
1344   - }
1345 1350
1346 1351 /**
1347 1352 * Sets ->pagetype from the script name. For example, if the script that was
@@ -1448,8 +1453,8 @@ protected function initialise_standard_body_classes() {
1448 1453 $this->add_body_class('drag');
1449 1454 }
1450 1455
1451   - if ($this->_legacythemeinuse) {
1452   - $this->add_body_class('legacytheme');
  1456 + if ($this->_devicetypeinuse != 'default') {
  1457 + $this->add_body_class($this->_devicetypeinuse . 'theme');
1453 1458 }
1454 1459 }
1455 1460
206 theme/index.php
@@ -23,29 +23,32 @@
23 23 require_once($CFG->libdir . '/adminlib.php');
24 24
25 25 $choose = optional_param('choose', '', PARAM_SAFEDIR);
26   -$chooselegacy = optional_param('chooselegacy', '', PARAM_SAFEDIR);
27 26 $reset = optional_param('reset', 0, PARAM_BOOL);
  27 +$device = optional_param('device', '', PARAM_TEXT);
28 28
29 29 admin_externalpage_setup('themeselector');
30 30
  31 +if (!empty($device)) {
  32 + // Make sure the device requested is valid
  33 + $devices = get_device_type_list();
  34 + if (!in_array($device, $devices)) {
  35 + // The provided device isn't a valid device throw an error
  36 + print_error('invaliddevicetype');
  37 + }
  38 +}
  39 +
31 40 unset($SESSION->theme);
32 41
33 42 if ($reset and confirm_sesskey()) {
34 43 theme_reset_all_caches();
35 44
36   -} else if (($choose || $chooselegacy) && confirm_sesskey()) {
37   -
38   - if ($choose) {
39   - $chosentheme = $choose;
40   - $heading = get_string('themesaved');
41   - $config = 'theme';
42   - } else {
43   - $chosentheme = $chooselegacy;
44   - $heading = get_string('legacythemesaved');
45   - $config = 'themelegacy';
46   - }
47   - $theme = theme_config::load($chosentheme);
48   - set_config($config, $theme->name);
  45 +} else if ($choose && $device && confirm_sesskey()) {
  46 +
  47 + // Load the theme to make sure it is valid.
  48 + $theme = theme_config::load($choose);
  49 + // Get the config argument for the chosen device.
  50 + $themename = get_device_cfg_var_name($device);
  51 + set_config($themename, $theme->name);
49 52
50 53 // Create a new page for the display of the themes readme.
51 54 // This ensures that the readme page is shown using the new theme.
@@ -61,87 +64,132 @@
61 64 $output = $confirmpage->get_renderer('core');
62 65
63 66 echo $output->header();
64   - echo $output->heading($heading);
  67 + echo $output->heading(get_string('themesaved'));
65 68 echo $output->box_start();
66   - echo format_text(get_string('choosereadme', 'theme_'.$CFG->theme), FORMAT_MOODLE);
  69 + echo format_text(get_string('choosereadme', 'theme_'.$theme->name), FORMAT_MOODLE);
67 70 echo $output->box_end();
68 71 echo $output->continue_button($CFG->wwwroot . '/' . $CFG->admin . '/index.php');
69 72 echo $output->footer();
70 73 exit;
71 74 }
72 75
73   -// Otherwise, show a list of themes.
  76 +// Otherwise, show either a list of devices, or is enabledevicedetection set to no or a
  77 +// device is specified show a list of themes.
  78 +
74 79 echo $OUTPUT->header('themeselector');
75 80 echo $OUTPUT->heading(get_string('themes'));
76 81
77   -echo $OUTPUT->single_button(new moodle_url('index.php', array('sesskey'=>sesskey(),'reset'=>1)), get_string('themeresetcaches', 'admin'));
  82 +echo $OUTPUT->single_button(new moodle_url('index.php', array('sesskey' => sesskey(), 'reset' => 1)), get_string('themeresetcaches', 'admin'));
78 83
79 84 $table = new html_table();
80   -$table->id = 'adminthemeselector';
81   -$table->head = array(get_string('theme'), get_string('info'));
82   -
83   -$themes = get_plugin_list('theme');
84   -
85   -foreach ($themes as $themename => $themedir) {
86   -
87   - // Load the theme config.
88   - try {
89   - $theme = theme_config::load($themename);
90   - } catch (Exception $e) {
91   - // Bad theme, just skip it for now.
92   - continue;
93   - }
94   - if ($themename !== $theme->name) {
95   - //obsoleted or broken theme, just skip for now
96   - continue;
  85 +$table->data = array();
  86 +if (!empty($CFG->enabledevicedetection) && empty($device)) {
  87 + // Display a list of devices that a user can select a theme for.
  88 +
  89 + $strthemenotselected = get_string('themenoselected', 'admin');
  90 + $strthemeselect = get_string('themeselect', 'admin');
  91 +
  92 + // Display the device selection screen
  93 + $table->id = 'admindeviceselector';
  94 + $table->head = array(get_string('devicetype', 'admin'), get_string('theme'), get_string('info'));
  95 +
  96 + $devices = get_device_type_list();
  97 + foreach ($devices as $device) {
  98 +
  99 + $themename = get_selected_theme_for_device_type($device);
  100 + if (!$themename && $device == 'default') {
  101 + $themename = theme_config::DEFAULT_THEME;
  102 + }
  103 +
  104 + $screenshotcell = $strthemenotselected;
  105 + if ($themename) {
  106 + // Check the theme exists
  107 + $themename = clean_param($themename, PARAM_THEME);
  108 + if (empty($themename)) {
  109 + // Likely the theme has been deleted
  110 + unset_config(get_device_cfg_var_name($device));
  111 + } else {
  112 + $strthemename = get_string('pluginname', 'theme_'.$themename);
  113 + // link to the screenshot, now mandatory - the image path is hardcoded because we need image from other themes, not the current one
  114 + $screenshoturl = new moodle_url('/theme/image.php', array('theme' => $themename, 'image' => 'screenshot', 'component' => 'theme'));
  115 + // Contents of the screenshot/preview cell.
  116 + $screenshotcell = html_writer::empty_tag('img', array('src' => $screenshoturl, 'alt' => $strthemename));
  117 + }
  118 + }
  119 +
  120 + $deviceurl = new moodle_url('/theme/index.php', array('device' => $device, 'sesskey' => sesskey()));
  121 + $select = new single_button($deviceurl, $strthemeselect, 'get');
  122 +
  123 + $table->data[] = array(
  124 + $device,
  125 + $screenshotcell,
  126 + $OUTPUT->render($select)
  127 + );
97 128 }
98   - if (!$CFG->themedesignermode && $theme->hidefromselector) {
99   - // The theme doesn't want to be shown in the theme selector and as theme
100   - // designer mode is switched off we will respect that decision.
101   - continue;
102   - }
103   - $strthemename = get_string('pluginname', 'theme_'.$themename);
104   -
105   - // Build the table row, and also a list of items to go in the second cell.
106   - $row = array();
107   - $infoitems = array();
108   - $rowclasses = array();
109   -
110   - // Set up bools whether this theme is chosen either main or legacy
111   - $ischosentheme = ($themename == $CFG->theme);
112   - $ischosenlegacytheme = (!empty($CFG->themelegacy) && $themename == $CFG->themelegacy);
  129 +} else {
  130 + // Either a device has been selected of $CFG->enabledevicedetection is off so display a list
  131 + // of themes to select.
113 132
114   - if ($ischosentheme) {
115   - // Is the chosen main theme
116   - $rowclasses[] = 'selectedtheme';
  133 + if (empty($device)) {
  134 + // if $CFG->enabledevicedetection is off this will return 'default'
  135 + $device = get_device_type();
117 136 }
118   - if ($ischosenlegacytheme) {
119   - // Is the chosen legacy theme
120   - $rowclasses[] = 'selectedlegacytheme';
121   - }
122   -
123   - // link to the screenshot, now mandatory - the image path is hardcoded because we need image from other themes, not the current one
124   - $screenshotpath = new moodle_url('/theme/image.php', array('theme'=>$themename, 'image'=>'screenshot','component'=>'theme'));
125   - // Contents of the first screenshot/preview cell.
126   - $row[] = html_writer::empty_tag('img', array('src'=>$screenshotpath, 'alt'=>$strthemename));
127 137
128   - // Contents of the second cell.
129   - $infocell = $OUTPUT->heading($strthemename, 3);
130   -
131   - // Button to choose this as the main theme
132   - $maintheme = new single_button(new moodle_url('/theme/index.php', array('choose' => $themename, 'sesskey' => sesskey())), get_string('useformaintheme'), 'get');
133   - $maintheme->disabled = $ischosentheme;
134   - $infocell .= $OUTPUT->render($maintheme);
135   -
136   - // Button to choose this as the legacy theme
137   - $legacytheme = new single_button(new moodle_url('/theme/index.php', array('chooselegacy' => $themename, 'sesskey' => sesskey())), get_string('useforlegacytheme'), 'get');
138   - $legacytheme->disabled = $ischosenlegacytheme;
139   - $infocell .= $OUTPUT->render($legacytheme);
140   -
141   - $row[] = $infocell;
142   -
143   - $table->data[$themename] = $row;
144   - $table->rowclasses[$themename] = join(' ', $rowclasses);
  138 + $table->id = 'adminthemeselector';
  139 + $table->head = array(get_string('theme'), get_string('info'));
  140 +
  141 + $themes = get_plugin_list('theme');
  142 +
  143 + foreach ($themes as $themename => $themedir) {
  144 +
  145 + // Load the theme config.
  146 + try {
  147 + $theme = theme_config::load($themename);
  148 + } catch (Exception $e) {
  149 + // Bad theme, just skip it for now.
  150 + continue;
  151 + }
  152 + if ($themename !== $theme->name) {
  153 + //obsoleted or broken theme, just skip for now
  154 + continue;
  155 + }
  156 + if (!$CFG->themedesignermode && $theme->hidefromselector) {
  157 + // The theme doesn't want to be shown in the theme selector and as theme
  158 + // designer mode is switched off we will respect that decision.
  159 + continue;
  160 + }
  161 + $strthemename = get_string('pluginname', 'theme_'.$themename);
  162 +
  163 + // Build the table row, and also a list of items to go in the second cell.
  164 + $row = array();
  165 + $infoitems = array();
  166 + $rowclasses = array();
  167 +
  168 + // Set up bools whether this theme is chosen either main or legacy
  169 + $ischosentheme = ($themename == get_selected_theme_for_device_type($device));
  170 +
  171 + if ($ischosentheme) {
  172 + // Is the chosen main theme
  173 + $rowclasses[] = 'selectedtheme';
  174 + }
  175 +
  176 + // link to the screenshot, now mandatory - the image path is hardcoded because we need image from other themes, not the current one
  177 + $screenshotpath = new moodle_url('/theme/image.php', array('theme'=>$themename, 'image'=>'screenshot', 'component'=>'theme'));
  178 + // Contents of the first screenshot/preview cell.
  179 + $row[] = html_writer::empty_tag('img', array('src'=>$screenshotpath, 'alt'=>$strthemename));
  180 + // Contents of the second cell.
  181 + $infocell = $OUTPUT->heading($strthemename, 3);
  182 +
  183 + // Button to choose this as the main theme
  184 + $maintheme = new single_button(new moodle_url('/theme/index.php', array('device' => $device, 'choose' => $themename, 'sesskey' => sesskey())), get_string('usetheme'), 'get');
  185 + $maintheme->disabled = $ischosentheme;
  186 + $infocell .= $OUTPUT->render($maintheme);
  187 +
  188 + $row[] = $infocell;
  189 +
  190 + $table->data[$themename] = $row;
  191 + $table->rowclasses[$themename] = join(' ', $rowclasses);
  192 + }
145 193 }
146 194
147 195 echo html_writer::table($table);
33 theme/switchdevice.php
... ... @@ -0,0 +1,33 @@
  1 +<?php
  2 +// This file is part of Moodle - http://moodle.org/
  3 +//
  4 +// Moodle is free software: you can redistribute it and/or modify
  5 +// it under the terms of the GNU General Public License as published by
  6 +// the Free Software Foundation, either version 3 of the License, or
  7 +// (at your option) any later version.
  8 +//
  9 +// Moodle is distributed in the hope that it will be useful,
  10 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 +// GNU General Public License for more details.
  13 +//
  14 +// You should have received a copy of the GNU General Public License
  15 +// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16 +
  17 +/**
  18 + * This code processes switch device requests-> ... -> Theme selector UI.
  19 + *
  20 + * This script doesn't require login as not logged in users should still
  21 + * be able to switch the device theme they are using.
  22 + */
  23 +
  24 +require('../config.php');
  25 +
  26 +$url = required_param('url', PARAM_LOCALURL);
  27 +$newdevice = required_param('device', PARAM_TEXT);
  28 +
  29 +require_sesskey();
  30 +
  31 +set_user_device_type($newdevice);
  32 +
  33 +redirect($url);
2  version.php
@@ -30,7 +30,7 @@
30 30 defined('MOODLE_INTERNAL') || die();
31 31
32 32
33   -$version = 2011060500.02; // YYYYMMDD = weekly release date of this DEV branch
  33 +$version = 2011060500.03; // YYYYMMDD = weekly release date of this DEV branch
34 34 // RR = release increments - 00 in DEV branches
35 35 // .XX = incremental changes
36 36

0 comments on commit 7bff544

Please sign in to comment.
Something went wrong with that request. Please try again.