From f8065dd2872e3108acd17b99a93274b93aca9d4c Mon Sep 17 00:00:00 2001 From: nicolasconnault Date: Mon, 27 Jul 2009 10:33:00 +0000 Subject: [PATCH] MDL-19756 Migrated the following functions from weblib to outputlib: 1. button_to_popup_window 2. link_to_popup_window 3. print_single_button 4. print_spacer 5. print_file_picture (deprecated) 6. print_user_picture 7. print_png (deprecated) 8. helpbutton 9. doclink 10. print_paging_bar 11. notice_yesno --- group/autogroup.php | 1 + group/autogroup_form.php | 3 +- help.php | 7 + index.php | 6 +- lang/en_utf8/help/group/namingscheme.html | 2 + lang/en_utf8/moodle.php | 1 + lib/ajax/ajaxlib.php | 15 +- lib/deprecatedlib.php | 596 +++++++++ lib/form/text.php | 2 +- lib/javascript-static.js | 131 +- lib/outputlib.php | 1353 ++++++++++++++++++++- lib/simpletest/testdeprecatedlib.php | 74 ++ lib/simpletest/testoutputlib.php | 252 +++- lib/simpletest/testweblib.php | 23 +- lib/simpletestlib.php | 81 +- lib/weblib.php | 846 +------------ theme/standard/styles_ie6.css | 5 +- theme/standard/styles_layout.css | 16 + 18 files changed, 2517 insertions(+), 897 deletions(-) create mode 100644 lang/en_utf8/help/group/namingscheme.html create mode 100644 lib/simpletest/testdeprecatedlib.php diff --git a/group/autogroup.php b/group/autogroup.php index 6a74cc8459..19a27290af 100644 --- a/group/autogroup.php +++ b/group/autogroup.php @@ -17,6 +17,7 @@ if (!defined('AUTOGROUP_MIN_RATIO')) { } $courseid = required_param('courseid', PARAM_INT); +$PAGE->set_url('/group/autogroup.php', array('courseid' => $courseid)); if (!$course = $DB->get_record('course', array('id'=>$courseid))) { print_error('invalidcourseid'); diff --git a/group/autogroup_form.php b/group/autogroup_form.php index 373901a2af..06887e6b38 100644 --- a/group/autogroup_form.php +++ b/group/autogroup_form.php @@ -45,8 +45,7 @@ class autogroup_form extends moodleform { $mform->setAdvanced('allocateby'); $mform->addElement('text', 'namingscheme', get_string('namingscheme', 'group')); - $mform->setHelpButton('namingscheme', array(false, get_string('namingschemehelp', 'group'), - false, true, false, get_string('namingschemehelp', 'group'))); + $mform->setHelpButton('namingscheme', array('namingscheme', get_string('namingschemehelp', 'group'), 'group')); $mform->addRule('namingscheme', get_string('required'), 'required', null, 'client'); $mform->setType('namingscheme', PARAM_MULTILANG); // there must not be duplicate group names in course diff --git a/help.php b/help.php index 93779336f0..655c8f54bf 100644 --- a/help.php +++ b/help.php @@ -19,6 +19,7 @@ $text = optional_param('text', 'No text to display', PARAM_CLEAN); $module = optional_param('module', 'moodle', PARAM_ALPHAEXT); $forcelang = optional_param('forcelang', '', PARAM_SAFEDIR); $skiplocal = optional_param('skiplocal', 0, PARAM_INT); // shall _local help files be skipped? +$fortooltip = optional_param('fortooltip', 0, PARAM_INT); $PAGE->set_course($COURSE); @@ -62,8 +63,14 @@ if (!empty($file)) { // Finish buffer $output = ob_get_contents(); + ob_end_clean(); +if ($fortooltip) { + echo shorten_text($output, 400, false, '' . get_string('clickhelpiconformoreinfo') . ''); + die(); +} + // Determine title $title = get_string('help'); // Default is just 'Help' $matches = array(); diff --git a/index.php b/index.php index bad1b72d4e..d92a85980d 100644 --- a/index.php +++ b/index.php @@ -66,6 +66,9 @@ add_to_log(SITEID, 'course', 'view', 'view.php?id='.SITEID, SITEID); } + $PAGE->set_pagetype('site-index'); + $PAGE->set_course($SITE); + if (empty($CFG->langmenu)) { $langmenu = ''; } else { @@ -74,9 +77,6 @@ $langlabel = get_accesshide(get_string('language')); $langmenu = popup_form($CFG->wwwroot .'/index.php?lang=', $langs, 'chooselang', $currlang, '', '', '', true, 'self', $langlabel); } - - $PAGE->set_pagetype('site-index'); - $PAGE->set_course($SITE); $PAGE->set_other_editing_capability('moodle/course:manageactivities'); $PAGE->set_url(''); $PAGE->set_docs_path(''); diff --git a/lang/en_utf8/help/group/namingscheme.html b/lang/en_utf8/help/group/namingscheme.html new file mode 100644 index 0000000000..4ee5a1b73b --- /dev/null +++ b/lang/en_utf8/help/group/namingscheme.html @@ -0,0 +1,2 @@ +

Naming scheme

+

Use @ character to represent the group letter (A-Z) or # to represent the group number.

diff --git a/lang/en_utf8/moodle.php b/lang/en_utf8/moodle.php index f4547f56bc..5eb64a8aec 100644 --- a/lang/en_utf8/moodle.php +++ b/lang/en_utf8/moodle.php @@ -242,6 +242,7 @@ $string['clamquarantinedirfailed'] = 'Could not move the file into your specifie $string['clamunknownerror'] = 'There was an unknown error with clam.'; $string['cleaningtempdata'] = 'Cleaning temp data'; $string['clear'] = 'Clear'; +$string['clickhelpiconformoreinfo'] = '... continues ... Click on the help icon to read the full article'; $string['clickhere'] = 'Click here ...'; $string['clicktochange'] = 'Click to change'; $string['clicktohideshow'] = 'Click to expand or collapse'; diff --git a/lib/ajax/ajaxlib.php b/lib/ajax/ajaxlib.php index 00d7f87b26..46a1805183 100644 --- a/lib/ajax/ajaxlib.php +++ b/lib/ajax/ajaxlib.php @@ -32,7 +32,7 @@ * @param page_requirements_manager $requires The page_requirements_manager to initialise. */ function setup_core_javascript(page_requirements_manager $requires) { - global $CFG; + global $CFG, $OUTPUT; // JavaScript should always work with $CFG->httpswwwroot rather than $CFG->wwwroot. // Otherwise, in some situations, users will get warnings about insecure content @@ -41,6 +41,7 @@ function setup_core_javascript(page_requirements_manager $requires) { $config = array( 'wwwroot' => $CFG->httpswwwroot, // Yes, really. See above. 'sesskey' => sesskey(), + 'loadingicon' => $OUTPUT->old_icon_url('i/loading_small') ); if (debugging('', DEBUG_DEVELOPER)) { $config['developerdebug'] = true; @@ -56,6 +57,12 @@ function setup_core_javascript(page_requirements_manager $requires) { // Note that, as a short-cut, the code // $js = "document.body.className += ' jsenabled';\n"; // is hard-coded in {@link page_requirements_manager::get_top_of_body_code) + $requires->yui_lib('container'); + $requires->yui_lib('connection'); + $requires->string_for_js('confirmation', 'moodle'); + $requires->string_for_js('cancel', 'moodle'); + $requires->string_for_js('yes', 'moodle'); + $requires->js_function_call('init_help_icons'); } @@ -364,8 +371,9 @@ class page_requirements_manager { * @return required_event_handler The event_handler object */ public function event_handler($id, $event, $function, $arguments=array()) { - $requirement = new required_event_handler($id, $event, $function, $arguments); + $requirement = new required_event_handler($this, $id, $event, $function, $arguments); $this->requiredjscode[] = $requirement; + $this->linkedrequirements[] = new required_yui_lib($this, 'event'); return $requirement; } @@ -1109,7 +1117,6 @@ class required_event_handler extends required_js_code { * @param array $arguments An optional array of argument parameters to pass to the function */ public function __construct(page_requirements_manager $manager, $id, $event, $function, $args=array()) { - $manager->requires->yui_lib('event'); parent::__construct($manager); $this->id = $id; $this->event = $event; @@ -1118,7 +1125,7 @@ class required_event_handler extends required_js_code { } public function get_js_code() { - $output = "YAHOO.util.Event.addListener($this->id, '$this->event', $this->function"; + $output = "YAHOO.util.Event.addListener('$this->id', '$this->event', $this->function"; if (!empty($this->args)) { $output .= ', ' . json_encode($this->args); } diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php index 44ed07e529..94098918ad 100644 --- a/lib/deprecatedlib.php +++ b/lib/deprecatedlib.php @@ -2379,3 +2379,599 @@ function print_table($table, $return=false) { return true; } } + +/** + * Creates and displays (or returns) a link to a popup window + * + * @deprecated since Moodle 2.0 + * + * @param string $url Web link. Either relative to $CFG->wwwroot, or a full URL. + * @param string $name Name to be assigned to the popup window (this is used by + * client-side scripts to "talk" to the popup window) + * @param string $linkname Text to be displayed as web link + * @param int $height Height to assign to popup window + * @param int $width Height to assign to popup window + * @param string $title Text to be displayed as popup page title + * @param string $options List of additional options for popup window + * @param bool $return If true, return as a string, otherwise print + * @param string $id id added to the element + * @param string $class class added to the element + * @return string html code to display a link to a popup window. + */ +function link_to_popup_window ($url, $name=null, $linkname=null, + $height=400, $width=500, $title=null, + $options=null, $return=false) { + global $OUTPUT; + + // debugging('link_to_popup_window() has been deprecated. Please change your code to use $OUTPUT->link_to_popup().'); + + if ($options == 'none') { + $options = null; + } + + if (empty($linkname)) { + throw new coding_exception('A link must have a descriptive text value! See $OUTPUT->link_to_popup() for usage.'); + } + + // Create a html_link object + $link = new html_link(); + $link->text = $linkname; + $link->url = $url; + $link->title = $title; + + // Parse the $options string + $popupparams = array(); + if (!empty($options)) { + $optionsarray = explode(',', $options); + foreach ($optionsarray as $option) { + if (strstr($option, '=')) { + $parts = explode('=', $option); + if ($parts[1] == '0') { + $popupparams[$parts[0]] = false; + } else { + $popupparams[$parts[0]] = $parts[1]; + } + } else { + $popupparams[$option] = true; + } + } + } + + $popupaction = new popup_action('click', $url, $name, $popupparams); + $link->add_action_object($popupaction); + + // Call the output method + $output = $OUTPUT->link_to_popup($link); + + if ($return) { + return $output; + } else { + echo $output; + } +} + +/** + * Creates and displays (or returns) a buttons to a popup window. + * + * @deprecated since Moodle 2.0 + * + * @param string $url Web link. Either relative to $CFG->wwwroot, or a full URL. + * @param string $name Name to be assigned to the popup window (this is used by + * client-side scripts to "talk" to the popup window) + * @param string $linkname Text to be displayed as web link + * @param int $height Height to assign to popup window + * @param int $width Height to assign to popup window + * @param string $title Text to be displayed as popup page title + * @param string $options List of additional options for popup window + * @param bool $return If true, return as a string, otherwise print + * @param string $id id added to the element + * @param string $class class added to the element + * @return string html code to display a link to a popup window. + */ +function button_to_popup_window ($url, $name=null, $linkname=null, + $height=400, $width=500, $title=null, $options=null, $return=false, + $id=null, $class=null) { + global $OUTPUT; + + // debugging('link_to_popup_window() has been deprecated. Please change your code to use $OUTPUT->link_to_popup().'); + + if ($options == 'none') { + $options = null; + } + + if (empty($linkname)) { + throw new coding_exception('A link must have a descriptive text value! See $OUTPUT->link_to_popup() for usage.'); + } + + // Create a html_button object + $button = new html_button(); + $button->value = $linkname; + $button->url = $url; + $button->id = $id; + $button->add_class($class); + $button->method = 'post'; + $button->title = $title; + + // Parse the $options string + $popupparams = array(); + if (!empty($options)) { + $optionsarray = explode(',', $options); + foreach ($optionsarray as $option) { + if (strstr($option, '=')) { + $parts = explode('=', $option); + if ($parts[1] == '0') { + $popupparams[$parts[0]] = false; + } else { + $popupparams[$parts[0]] = $parts[1]; + } + } else { + $popupparams[$option] = true; + } + } + } + + if (!empty($height)) { + $popupparams['height'] = $height; + } + if (!empty($width)) { + $popupparams['width'] = $width; + } + + $popupaction = new popup_action('click', $url, $name, $popupparams); + $button->add_action_object($popupaction); + $output = $OUTPUT->button($button); + + if ($return) { + return $output; + } else { + echo $output; + } +} + +/** + * Print a self contained form with a single submit button. + * + * @deprecated since Moodle 2.0 + * + * @param string $link used as the action attribute on the form, so the URL that will be hit if the button is clicked. + * @param array $options these become hidden form fields, so these options get passed to the script at $link. + * @param string $label the caption that appears on the button. + * @param string $method HTTP method used on the request of the button is clicked. 'get' or 'post'. + * @param string $notusedanymore no longer used. + * @param boolean $return if false, output the form directly, otherwise return the HTML as a string. + * @param string $tooltip a tooltip to add to the button as a title attribute. + * @param boolean $disabled if true, the button will be disabled. + * @param string $jsconfirmmessage if not empty then display a confirm dialogue with this string as the question. + * @param string $formid The id attribute to use for the form + * @return string|void Depending on the $return paramter. + */ +function print_single_button($link, $options, $label='OK', $method='get', $notusedanymore='', + $return=false, $tooltip='', $disabled = false, $jsconfirmmessage='', $formid = '') { + global $OUTPUT; + + // debugging('print_single_button() has been deprecated. Please change your code to use $OUTPUT->button().'); + + // Cast $options to array + $options = (array) $options; + $form = new html_form(); + $form->url = new moodle_url($link, $options); + $form->button->label = $label; + $form->button->disabled = $disabled; + $form->button->title = $tooltip; + $form->method = $method; + $form->id = $formid; + + if ($jsconfirmmessage) { + $confirmaction = new component_action('click', 'confirm_dialog', array($jsconfirmmessage)); + $form->button->add_action_object($confirmaction); + } + + $output = $OUTPUT->button($form); + + if ($return) { + return $output; + } else { + echo $output; + } +} + +/** + * Print a spacer image with the option of including a line break. + * + * @deprecated since Moodle 2.0 + * + * @global object + * @param int $height The height in pixels to make the spacer + * @param int $width The width in pixels to make the spacer + * @param boolean $br If set to true a BR is written after the spacer + */ +function print_spacer($height=1, $width=1, $br=true, $return=false) { + global $CFG, $OUTPUT; + + // debugging('print_spacer() has been deprecated. Please change your code to use $OUTPUT->spacer().'); + + $spacer = new html_spacer(); + $spacer->height = $height; + $spacer->width = $width; + + $output = $OUTPUT->spacer($spacer); + + $output .= ''; + + if ($br) { + $output .= '
'; + } + + if ($return) { + return $output; + } else { + echo $output; + } +} + +/** + * Given the path to a picture file in a course, or a URL, + * this function includes the picture in the page. + * + * @deprecated since Moodle 2.0 + */ +function print_file_picture($path, $courseid=0, $height='', $width='', $link='', $return=false) { + throw new coding_exception('print_file_picture() has been deprecated since Moodle 2.0. Please use $OUTPUT->action_icon() instead.'); +} + +/** + * Print the specified user's avatar. + * + * @deprecated since Moodle 2.0 + * + * @global object + * @global object + * @param mixed $user Should be a $user object with at least fields id, picture, imagealt, firstname, lastname + * If any of these are missing, or if a userid is passed, the the database is queried. Avoid this + * if at all possible, particularly for reports. It is very bad for performance. + * @param int $courseid The course id. Used when constructing the link to the user's profile. + * @param boolean $picture The picture to print. By default (or if NULL is passed) $user->picture is used. + * @param int $size Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatibility + * @param boolean $return If false print picture to current page, otherwise return the output as string + * @param boolean $link enclose printed image in a link the user's profile (default true). + * @param string $target link target attribute. Makes the profile open in a popup window. + * @param boolean $alttext add non-blank alt-text to the image. (Default true, set to false for purely + * decorative images, or where the username will be printed anyway.) + * @return string|void String or nothing, depending on $return. + */ +function print_user_picture($user, $courseid, $picture=NULL, $size=0, $return=false, $link=true, $target='', $alttext=true) { + global $CFG, $DB, $OUTPUT; + + // debugging('print_user_picture() has been deprecated. Please change your code to use $OUTPUT->user_picture($user, $link, $popup).'); + + $userpic = new user_picture(); + $userpic->user = $user; + $userpic->courseid = $courseid; + $userpic->size = $size; + $userpic->link = $link; + $userpic->alttext = $alttext; + + if (!empty($picture)) { + $userpic->image = new html_image(); + $userpic->image->src = $picture; + } + + if (!empty($target)) { + $popupaction = new popup_action('click', new moodle_url($target)); + $userpic->add_action_object($popupaction); + } + + $output = $OUTPUT->user_picture($userpic); + + if ($return) { + return $output; + } else { + echo $output; + } +} + +/** + * Print a png image. + * + * @deprecated since Moodle 2.0: no replacement + * + */ +function print_png() { + throw new coding_exception('print_png() has been deprecated since Moodle 2.0. Please use $OUTPUT->image() instead.'); +} + + +/** + * Prints a basic textarea field. + * + * @deprecated since Moodle 2.0 + * + * When using this function, you should + * + * @global object + * @param bool $usehtmleditor Enables the use of the htmleditor for this field. + * @param int $rows Number of rows to display (minimum of 10 when $height is non-null) + * @param int $cols Number of columns to display (minimum of 65 when $width is non-null) + * @param null $width (Deprecated) Width of the element; if a value is passed, the minimum value for $cols will be 65. Value is otherwise ignored. + * @param null $height (Deprecated) Height of the element; if a value is passe, the minimum value for $rows will be 10. Value is otherwise ignored. + * @param string $name Name to use for the textarea element. + * @param string $value Initial content to display in the textarea. + * @param int $obsolete deprecated + * @param bool $return If false, will output string. If true, will return string value. + * @param string $id CSS ID to add to the textarea element. + * @return string|void depending on the value of $return + */ +function print_textarea($usehtmleditor, $rows, $cols, $width, $height, $name, $value='', $obsolete=0, $return=false, $id='') { + /// $width and height are legacy fields and no longer used as pixels like they used to be. + /// However, you can set them to zero to override the mincols and minrows values below. + + // debugging('print_textarea() has been deprecated. Please change your code to use $OUTPUT->textarea().'); + + global $CFG; + + $mincols = 65; + $minrows = 10; + $str = ''; + + if ($id === '') { + $id = 'edit-'.$name; + } + + if ($usehtmleditor) { + if ($height && ($rows < $minrows)) { + $rows = $minrows; + } + if ($width && ($cols < $mincols)) { + $cols = $mincols; + } + } + + if ($usehtmleditor) { + editors_head_setup(); + $editor = get_preferred_texteditor(FORMAT_HTML); + $editor->use_editor($id, array('legacy'=>true)); + } else { + $editorclass = ''; + } + + $str .= "\n".''."\n"; + + if ($return) { + return $str; + } + echo $str; +} + + +/** + * Print a help button. + * + * @deprecated since Moodle 2.0 + * + * @param string $page The keyword that defines a help page + * @param string $title The title of links, rollover tips, alt tags etc + * 'Help with' (or the language equivalent) will be prefixed and '...' will be stripped. + * @param string $module Which module is the page defined in + * @param mixed $image Use a help image for the link? (true/false/"both") + * @param boolean $linktext If true, display the title next to the help icon. + * @param string $text If defined then this text is used in the page, and + * the $page variable is ignored. DEPRECATED! + * @param boolean $return If true then the output is returned as a string, if false it is printed to the current page. + * @param string $imagetext The full text for the helpbutton icon. If empty use default help.gif + * @return string|void Depending on value of $return + */ +function helpbutton($page, $title, $module='moodle', $image=true, $linktext=false, $text='', $return=false, $imagetext='') { + // debugging('helpbutton() has been deprecated. Please change your code to use $OUTPUT->help_icon().'); + + global $OUTPUT; + + if (!empty($text)) { + throw new coding_exception('The $text parameter has been deprecated. Please update your code and use $OUTPUT->help_icon() instead.
' . + "You will also need to copy the following text into a proper html help file if not already done so:

$text

"); + } + + if (!empty($imagetext)) { + throw new coding_exception('The $imagetext parameter has been deprecated. Please update your code and use $OUTPUT->help_icon() instead.'); + } + + $helpicon = new help_icon(); + $helpicon->page = $page; + $helpicon->module = $module; + $helpicon->text = $title; + $helpicon->linktext = $linktext; + + // If image is true, the defaults are handled by the helpicon's prepare method + if (!$image) { + $helpicon->image = false; + } + + $output = $OUTPUT->help_icon($helpicon); + + if ($return) { + return $output; + } else { + echo $output; + } + +} + +/** + * Returns an image of an up or down arrow, used for column sorting. To avoid unnecessary DB accesses, please + * provide this function with the language strings for sortasc and sortdesc. + * + * @deprecated since Moodle 2.0 + * + * TODO migrate to outputlib + * If no sort string is associated with the direction, an arrow with no alt text will be printed/returned. + * + * @global object + * @param string $direction 'up' or 'down' + * @param string $strsort The language string used for the alt attribute of this image + * @param bool $return Whether to print directly or return the html string + * @return string|void depending on $return + * + */ +function print_arrow($direction='up', $strsort=null, $return=false) { + // debugging('print_arrow() has been deprecated. Please change your code to use $OUTPUT->arrow().'); + + global $OUTPUT; + + if (!in_array($direction, array('up', 'down', 'right', 'left', 'move'))) { + return null; + } + + $return = null; + + switch ($direction) { + case 'up': + $sortdir = 'asc'; + break; + case 'down': + $sortdir = 'desc'; + break; + case 'move': + $sortdir = 'asc'; + break; + default: + $sortdir = null; + break; + } + + // Prepare language string + $strsort = ''; + if (empty($strsort) && !empty($sortdir)) { + $strsort = get_string('sort' . $sortdir, 'grades'); + } + + $return = ' '.$strsort.' '; + + if ($return) { + return $return; + } else { + echo $return; + } +} + +/** + * Returns a string containing a link to the user documentation. + * Also contains an icon by default. Shown to teachers and admin only. + * + * @deprecated since Moodle 2.0 + * + * @global object + * @param string $path The page link after doc root and language, no leading slash. + * @param string $text The text to be displayed for the link + * @param string $iconpath The path to the icon to be displayed + * @return string Either the link or an empty string + */ +function doc_link($path='', $text='', $iconpath='') { + global $CFG, $OUTPUT; + + // debugging('doc_link() has been deprecated. Please change your code to use $OUTPUT->action_icon().'); + + if (empty($CFG->docroot)) { + return ''; + } + + $icon = new action_icon(); + $icon->linktext = $text; + + if (!empty($iconpath)) { + $icon->image->src = $iconpath; + $icon->image->alt = $text; + $icon->image->add_class('iconhelp'); + } else { + $icon->image->src = $CFG->httpswwwroot . '/pix/docs.gif'; + } + + $icon->link->url = new moodle_url(get_docs_url($path)); + + if (!empty($CFG->doctonewwindow)) { + $icon->actions[] = new popup_action('click', $icon->link->url); + } + + return $OUTPUT->action_icon($icon); +} + +/** + * Prints a single paging bar to provide access to other pages (usually in a search) + * + * @deprecated since Moodle 2.0 + * + * @param int $totalcount Thetotal number of entries available to be paged through + * @param int $page The page you are currently viewing + * @param int $perpage The number of entries that should be shown per page + * @param mixed $baseurl If this is a string then it is the url which will be appended with $pagevar, an equals sign and the page number. + * If this is a moodle_url object then the pagevar param will be replaced by the page no, for each page. + * @param string $pagevar This is the variable name that you use for the page number in your code (ie. 'tablepage', 'blogpage', etc) + * @param bool $nocurr do not display the current page as a link + * @param bool $return whether to return an output string or echo now + * @return bool|string depending on $result + */ +function print_paging_bar($totalcount, $page, $perpage, $baseurl, $pagevar='page',$nocurr=false, $return=false) { + global $OUTPUT; + + // debugging('print_paging_bar() has been deprecated. Please change your code to use $OUTPUT->paging_bar($pagingbar).'); + + $pagingbar = new moodle_paging_bar(); + $pagingbar->totalcount = $totalcount; + $pagingbar->page = $page; + $pagingbar->perpage = $perpage; + $pagingbar->baseurl = $baseurl; + $pagingbar->pagevar = $pagevar; + $pagingbar->nocurr = $nocurr; + $output = $OUTPUT->paging_bar($pagingbar); + + if ($return) { + return $output; + } + + echo $output; + return true; +} + +/** + * Print a message along with "Yes" and "No" links for the user to continue. + * + * @deprecated since Moodle 2.0 + * + * @global object + * @param string $message The text to display + * @param string $linkyes The link to take the user to if they choose "Yes" + * @param string $linkno The link to take the user to if they choose "No" + * @param string $optionyes The yes option to show on the notice + * @param string $optionsno The no option to show + * @param string $methodyes Form action method to use if yes [post, get] + * @param string $methodno Form action method to use if no [post, get] + * @return void Output is echo'd + */ +function notice_yesno($message, $linkyes, $linkno, $optionsyes=NULL, $optionsno=NULL, $methodyes='post', $methodno='post') { + + // debugging('notice_yesno() has been deprecated. Please change your code to use $OUTPUT->confirm($message, $buttoncontinue, $buttoncancel).'); + + global $OUTPUT; + + $buttoncontinue = new html_button(); + $buttoncontinue->url = new moodle_url($linkyes, $optionsyes); + $buttoncontinue->method = $methodyes; + $buttoncancel = new html_button(); + $buttoncancel->url = new moodle_url($linkno, $optionsno); + $buttoncancel->method = $methodno; + + echo $OUTPUT->confirm($message, $buttoncontinue, $buttoncancel); +} + +/** + * Prints a scale menu (as part of an existing form) including help button + * @deprecated since Moodle 2.0 + */ +function print_scale_menu() { + throw new coding_exception('print_scale_menu() has been deprecated since the Jurassic period. Get with the times!.'); +} + diff --git a/lib/form/text.php b/lib/form/text.php index 32f48d52b3..5b9a20d315 100644 --- a/lib/form/text.php +++ b/lib/form/text.php @@ -94,4 +94,4 @@ class MoodleQuickForm_text extends HTML_QuickForm_text{ return 'default'; } } -} \ No newline at end of file +} diff --git a/lib/javascript-static.js b/lib/javascript-static.js index 3ecb278052..fe6cd44903 100644 --- a/lib/javascript-static.js +++ b/lib/javascript-static.js @@ -560,7 +560,7 @@ date_selector_calendar.document_click = function(event) { date_selector_calendar.currentowner.release_calendar(); } } -} +} date_selector_calendar.prototype.claim_calendar = function() { date_selector_calendar.cancel_any_timeout(); @@ -733,12 +733,15 @@ function getElementsByClassName(oElm, strTagName, oClassNames) { return (arrReturnElements) } -function openpopup(url, name, options, fullscreen) { - var fullurl = url; - if (!url.match(/https?:\/\//)) { - fullurl = moodle_cfg.wwwroot + url; +function openpopup(event, args) { + + YAHOO.util.Event.preventDefault(event); + + var fullurl = args.url; + if (!args.url.match(/https?:\/\//)) { + fullurl = moodle_cfg.wwwroot + args.url; } - var windowobj = window.open(fullurl,name,options); + var windowobj = window.open(fullurl,args.name,args.options); if (!windowobj) { return true; } @@ -812,7 +815,7 @@ function set_user_preference(name, value) { } // Make the request. - YAHOO.util.Connect.asyncRequest('GET', url, callback); + YAHOO.util.Connect.asyncRequest('GET', url, callback); } } @@ -886,7 +889,7 @@ function collapsible_region(id, userpref, strtooltip, collapsedicon, expandedico collapsible_region.prototype.userpref = null; /** - * The key divs that make up this + * The key divs that make up this * @property div, innerdiv, captiondiv * @type HTMLDivElement */ @@ -895,7 +898,7 @@ collapsible_region.prototype.innerdiv = null; collapsible_region.prototype.captiondiv = null; /** - * The key divs that make up this + * The key divs that make up this * @property icon * @type HTMLImageElement */ @@ -1102,3 +1105,113 @@ function build_querystring(obj) { } return list.join('&'); } +/** + * Finds all help icons on the page and initiates YUI tooltips for + * each of them, which load a truncated version of the help's content + * on-the-fly asynchronously + */ +function init_help_icons() { + // var logger = new YAHOO.widget.LogReader(document.body, {draggable: true}); + + var iconspans = YAHOO.util.Dom.getElementsByClassName('helplink', 'span'); + + var tooltip = new YAHOO.widget.Tooltip('help_icon_tooltip', { + context: iconspans, + showdelay: 100, + hidedelay: 150, + autodismissdelay: 50000, + underlay: 'none' + }); + + tooltip.contextTriggerEvent.subscribe( + function(type, args) { + // Fetch help page contents asynchronously + // Load spinner icon while content is loading + var spinner = document.createElement('img'); + spinner.src = moodle_cfg.loadingicon; + + this.cfg.setProperty('text', spinner); + + var context = args[0]; + context.title = ''; + + var link = context.getElementsByTagName('a')[0]; + link.title = ''; + YAHOO.util.Dom.getElementsByClassName('iconhelp', 'img', link)[0].title = ''; + var thistooltip = this; + var ajaxurl = link.href + '&fortooltip=1'; + + + var callback = { + success: function(o) { + thistooltip.cfg.setProperty('text', o.responseText); + }, + failure: function(o) { + var debuginfo = o.statusText; + if (moodle_cfg.developerdebug) { + o.statusText += ' (' + ajaxurl + ')'; + } + thistooltip.cfg.setProperty('text', debuginfo); + } + }; + + var conn = YAHOO.util.Connect.asyncRequest("get", ajaxurl, callback); + } + ); +} + +/** + * Prints a confirmation dialog in the style of DOM.confirm(). + * @param object event A DOM event + * @param string message The message to show in the dialog + * @param string url The URL to forward to if YES is clicked. Disabled if fn is given + * @param function fn A JS function to run if YES is clicked. + */ +function confirm_dialog(event, message) { + + YAHOO.util.Event.preventDefault(event); + + var simpledialog = new YAHOO.widget.SimpleDialog('confirmdialog', + { width: '300px', + fixedcenter: true, + modal: true, + visible: false, + draggable: false + } + ); + + simpledialog.setHeader(mstr.moodle.confirmation); + simpledialog.setBody(message); + simpledialog.cfg.setProperty('icon', YAHOO.widget.SimpleDialog.ICON_WARN); + + var handle_cancel = function() { + this.hide(); + }; + + var handle_yes = function() { + this.hide(); + var target = event.target; + + if (target.tagName.toLowerCase() == 'a') { + window.location = target.href; + } else if (target.tagName.toLowerCase() == 'input') { + var parentelement = target.parentNode; + while (parentelement.tagName.toLowerCase() != 'form' && parentelement.tagName.toLowerCase() != 'body') { + parentelement = parentelement.parentNode; + } + if (parentelement.tagName.toLowerCase() == 'form') { + parentelement.submit(); + } + } else if(moodle_cfg.developerdebug) { + alert("Element of type " + target.tagName + " is not supported by the confirm_dialog function. Use A or INPUT"); + } + }; + + var buttons = [ { text: mstr.moodle.cancel, handler: handle_cancel, isDefault: true }, + { text: mstr.moodle.yes, handler: handle_yes } ]; + + simpledialog.cfg.queueProperty('buttons', buttons); + + simpledialog.render(document.body); + simpledialog.show(); +} diff --git a/lib/outputlib.php b/lib/outputlib.php index 1b55468f1b..c098cd9a26 100644 --- a/lib/outputlib.php +++ b/lib/outputlib.php @@ -15,6 +15,13 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . +/** + * This constant is used for html attributes which need to have an empty + * value and still be output by the renderers (e.g. alt=""); + * + * @constant @EMPTY@ + */ +define('HTML_ATTR_EMPTY', '@EMPTY@'); /** * Functions for generating the HTML that Moodle should output. @@ -27,7 +34,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - /** * A renderer factory is just responsible for creating an appropriate renderer * for any given part of Moodle. @@ -1306,7 +1312,9 @@ class moodle_renderer_base { */ protected function output_attribute($name, $value) { $value = trim($value); - if ($value || is_numeric($value)) { // We want 0 to be output. + if ($value == HTML_ATTR_EMPTY) { + return ' ' . $name . '=""'; + } else if ($value || is_numeric($value)) { // We want 0 to be output. return ' ' . $name . '="' . $value . '"'; } } @@ -1365,6 +1373,25 @@ class moodle_renderer_base { public function mod_icon_url($iconname, $module) { return $this->page->theme->mod_icon_url($iconname, $module); } + + /** + * A helper function that takes a moodle_html_component subclass as param. + * If that component has an id attribute and an array of valid component_action objects, + * it sets up the appropriate event handlers. + * + * @param moodle_html_component $component + * @return void; + */ + public function prepare_event_handlers(&$component) { + $actions = $component->get_actions(); + if (!empty($actions) && is_array($actions) && $actions[0] instanceof component_action) { + foreach ($actions as $action) { + if (!empty($action->jsfunction)) { + $this->page->requires->event_handler($component->id, $action->event, $action->jsfunction, $action->jsfunctionargs); + } + } + } + } } @@ -2189,6 +2216,7 @@ class moodle_core_renderer extends moodle_renderer_base { $this->page->set_state(moodle_page::STATE_DONE); + return $output . $footer; } @@ -2324,12 +2352,325 @@ class moodle_core_renderer extends moodle_renderer_base { return $output; } - public function link_to_popup_window() { + /** + * Given a html_textarea object, outputs an tag that uses the object's attributes. + * + * @param mixed $link A html_link object or a string URL (text param required in second case) + * @param string $text A descriptive text for the link. If $link is a html_link, this is not required. + * @return string HTML fragment + */ + public function textarea($textarea) { + + } + + /** + * Given a html_link object, outputs an tag that uses the object's attributes. + * + * @param mixed $link A html_link object or a string URL (text param required in second case) + * @param string $text A descriptive text for the link. If $link is a html_link, this is not required. + * @return string HTML fragment + */ + public function link($link, $text=null) { + $attributes = array('href' => $link); + + if (is_a($link, 'html_link')) { + $link->prepare(); + $attributes['href'] = prepare_url($link->url); + $text = $link->text; + + $attributes['class'] = $link->get_classes_string(); + $attributes['title'] = $link->title; + $attributes['id'] = $link->id; + + } else if (empty($text)) { + throw new coding_exception('$OUTPUT->link() must have a string as second parameter if the first param ($link) is a string'); + } + + return $this->output_tag('a', $attributes, $text); + } + + /** + * Print a message along with button choices for Continue/Cancel. Labels default to Yes(Continue)/No(Cancel). + * If a string or moodle_url is given instead of a html_button, method defaults to post and text to Yes/No + * @param string $message The question to ask the user + * @param mixed $continue The html_form component representing the Continue answer. Can also be a moodle_url or string URL + * @param mixed $cancel The html_form component representing the Cancel answer. Can also be a moodle_url or string URL + * @return string HTML fragment + */ + public function confirm($message, $continue, $cancel) { + if (!($continue instanceof html_form) && !is_object($continue)) { + $continueform = new html_form(); + $continueform->url = new moodle_url($continue); + $continue = $continueform; + } else { + throw new coding_exception('The 2nd and 3rd params to $OUTPUT->confirm must be either a URL (string/moodle_url) or a html_form object.'); + } + + if (!($cancel instanceof html_form) && !is_object($cancel)) { + $cancelform = new html_form(); + $cancelform->url = new moodle_url($cancel); + $cancel = $cancelform; + } + + if (empty($continue->button->label)) { + $continue->button->label = get_string('yes'); + } + if (empty($cancel->button->label)) { + $cancel->button->label = get_string('no'); + } + + $output = $this->box_start('generalbox', 'notice'); + $output .= $this->output_tag('p', array(), $message); + $output .= $this->output_tag('div', array('class' => 'buttons'), $this->button($continue) . $this->button($cancel)); + $output .= $this->box_end(); + return $output; + } + + /** + * Given a html_form object, outputs an tag within a form that uses the object's attributes. + * + * @param html_form $form A html_form object + * @return string HTML fragment + */ + public function button($form) { + if (empty($form->button)) { + throw new coding_exception('$OUTPUT->button($form) requires $form to have a button (html_button) value'); + } + + $form->button->prepare(); + + $this->prepare_event_handlers($form->button); + + $buttonattributes = array('class' => $form->button->get_classes_string(), + 'type' => 'submit', + 'value' => $form->button->label, + 'disabled' => $form->button->disabled, + 'id' => $form->button->id); + + $buttonoutput = $this->output_empty_tag('input', $buttonattributes); + + return $this->form($form, $buttonoutput); + } + + /** + * Given a html_form component and an optional rendered submit button, + * outputs a HTML form with correct divs and inputs and a single submit button. + * This doesn't render any other visible inputs. Use moodleforms for these. + * @param html_form $form A html_form instance + * @param string $contents HTML fragment to put inside the form. If given, must contain at least the submit button. + * @return string HTML fragment + */ + public function form($form, $contents=null) { + $form->prepare(); + + $this->prepare_event_handlers($form); + + if (empty($contents)) { + $contents = $this->output_empty_tag('input', array('type' => 'submit', 'value' => get_string('ok'))); + } + + $hiddenoutput = ''; + + foreach ($form->url->params() as $var => $val) { + $hiddenoutput .= $this->output_empty_tag('input', array('type' => 'hidden', 'name' => $var, 'value' => $val)); + } + + $formattributes = array( + 'method' => $form->method, + 'action' => prepare_url($form->url, true), + 'id' => $form->id, + 'class' => $form->get_classes_string()); + + $divoutput = $this->output_tag('div', array(), $hiddenoutput . $contents); + $formoutput = $this->output_tag('form', $formattributes, $divoutput); + $output = $this->output_tag('div', array('class' => 'singlebutton'), $formoutput); + + return $output; + } + + /** + * Given a action_icon object, outputs an image linking to an action (URL or AJAX). + * + * @param action_icon $icon An action_icon object + * @return string HTML fragment + */ + public function action_icon($icon) { + + $icon->prepare(); + + $this->prepare_event_handlers($icon); + + $imageoutput = $this->image($icon->image); + + if ($icon->linktext) { + $imageoutput .= $icon->linktext; + } + + $icon->link->text = $imageoutput; + + return $this->link($icon->link); + } + + /** + * Print a help icon. + * + * @param help_icon $helpicon A help_icon object, subclass of html_link + * + * @return string HTML fragment + */ + public function help_icon($icon) { + global $COURSE; + + $icon->prepare(); + + $icon->link->add_action_object(new popup_action('click', $icon->link->url)); + + $image = null; + + if (!empty($icon->image)) { + $image = $icon->image; + $image->add_class('iconhelp'); + } + + return $this->output_tag('span', array('class' => 'helplink'), $this->link_to_popup($icon->link, $image)); + } + + /** + * Creates and returns a button to a popup window + * + * @param html_link $link Subclass of moodle_html_component + * @param moodle_popup $popup A moodle_popup object + * @param html_image $image An optional image replacing the link text + * + * @return string HTML fragment + */ + public function link_to_popup($link, $image=null) { + $link->prepare(); + + $this->prepare_event_handlers($link); + + if (empty($link->url)) { + throw new coding_exception('Called $OUTPUT->link_to_popup($link) method without $link->url set.'); + } + + $linkurl = prepare_url($link->url); + + $tagoptions = array( + 'title' => $link->title, + 'id' => $link->id, + 'href' => ($linkurl) ? $linkurl : prepare_url($popup->url), + 'class' => $link->get_classes_string()); + + // Use image if one is given + if (!empty($image) && $image instanceof html_image) { + + if (empty($image->alt)) { + $image->alt = $link->text; + } + + $link->text = $this->image($image); + + if (!empty($link->linktext)) { + $link->text = "$link->title   $link->text"; + } + } + + return $this->output_tag('a', $tagoptions, $link->text); + } + + /** + * Creates and returns a spacer image with optional line break. + * + * @param html_image $image Subclass of moodle_html_component + * + * @return string HTML fragment + */ + public function spacer($image) { + $image->prepare(); + $image->add_class('spacer'); + + if (empty($image->src)) { + $image->src = $this->old_icon_url('spacer'); + } + + $output = $this->image($image); + + return $output; + } + + /** + * Creates and returns an image. + * + * @param html_image $image Subclass of moodle_html_component + * + * @return string HTML fragment + */ + public function image($image) { + $image->prepare(); + + $attributes = array('class' => $image->get_classes_string(), + 'style' => prepare_legacy_width_and_height($image), + 'src' => prepare_url($image->src), + 'alt' => $image->alt, + 'title' => $image->title); + return $this->output_empty_tag('img', $attributes); } - public function button_to_popup_window() { + /** + * Print the specified user's avatar. + * + * This method can be used in two ways: + *
+     * // Option 1:
+     * $userpic = new user_picture();
+     * // Set properties of $userpic
+     * $OUTPUT->user_picture($userpic);
+     *
+     * // Option 2: (shortcut for simple cases)
+     * // $user has come from the DB and has fields id, picture, imagealt, firstname and lastname
+     * $OUTPUT->user_picture($user, $COURSE->id);
+     * 
+ * + * @param object $userpic Object with at least fields id, picture, imagealt, firstname, lastname + * If any of these are missing, or if a userid is passed, the database is queried. Avoid this + * if at all possible, particularly for reports. It is very bad for performance. + * A user_picture object is a better parameter. + * @param int $courseid courseid Used when constructing the link to the user's profile. Required if $userpic + * is not a user_picture object + * @return string HTML fragment + */ + public function user_picture($userpic, $courseid=null) { + // Instantiate a user_picture object if $user is not already one + if (!($userpic instanceof user_picture)) { + if (empty($courseid)) { + throw new coding_exception('Called $OUTPUT->user_picture with a $user object but no $courseid.'); + } + + $user = $userpic; + $userpic = new user_picture(); + $userpic->user = $user; + $userpic->courseid = $courseid; + } + + $userpic->prepare(); + + $output = $this->image($userpic->image); + if (!empty($userpic->link) && !empty($userpic->url)) { + $actions = $userpic->get_actions(); + if (!empty($actions)) { + $link = new html_link(); + $link->url = $userpic->url; + $link->text = fullname($userpic->user); + $link->add_action_object($actions[0]); + $output = $this->link_to_popup($link); + } else { + $output = $this->link(prepare_url($userpic->url), $output); + } + } + + return $output; } public function close_window_button($buttontext = null, $reloadopener = false) { @@ -2506,8 +2847,55 @@ class moodle_core_renderer extends moodle_renderer_base { if (!is_a($link, 'moodle_url')) { $link = new moodle_url($link); } - return $this->output_tag('div', array('class' => 'continuebutton'), - print_single_button($link->out(true), $link->params(), get_string('continue'), 'get', '', true)); + $form = new html_form(); + $form->url = $link; + $form->values = $link->params(); + $form->button->label = get_string('continue'); + $form->method = 'get'; + + return $this->output_tag('div', array('class' => 'continuebutton') , $this->button($form)); + } + + /** + * Print a continue button that goes to a particular URL. + * + * @param string|moodle_url $link The url the button goes to. + * @return string the HTML to output. + */ + public function paging_bar($pagingbar) { + $output = ''; + + $pagingbar->prepare(); + + if ($pagingbar->totalcount > $pagingbar->perpage) { + $output .= get_string('page') . ':'; + + if (!empty($pagingbar->previouslink)) { + $output .= ' (' . $this->link($pagingbar->previouslink) . ') '; + } + + if (!empty($pagingbar->firstlink)) { + $output .= ' ' . $this->link($pagingbar->firstlink) . ' ...'; + } + + foreach ($pagingbar->pagelinks as $link) { + if ($link instanceof html_link) { + $output .= '  ' . $this->link($link); + } else { + $output .= "  $link"; + } + } + + if (!empty($pagingbar->lastlink)) { + $output .= ' ...' . $this->link($pagingbar->lastlink) . ' '; + } + + if (!empty($pagingbar->nextlink)) { + $output .= '  (' . $this->link($pagingbar->nextlink) . ')'; + } + } + + return $this->output_tag('div', array('class' => 'paging'), $output); } /** @@ -2711,6 +3099,7 @@ class moodle_core_renderer extends moodle_renderer_base { } } +/// COMPONENTS /** * Base class for classes representing HTML elements, like moodle_select_menu. @@ -2730,6 +3119,20 @@ class moodle_html_component { * @var array class names to add to this HTML element. */ public $classes = array(); + /** + * @var string $title The title attributes applicable to any XHTML element + */ + public $title = ''; + /** + * An optional array of component_action objects handling the action part of this component. + * @var array $actions + */ + protected $actions = array(); + /** + * This array of generated ids is kept static to avoid id collisions + * @var array $generated_ids + */ + public static $generated_ids = array(); /** * Ensure some class names are an array. @@ -2807,6 +3210,59 @@ class moodle_html_component { } } + /** + * Adds a JS action to this component. + * Note: the JS function you write must have only two arguments: (string)event and (object|array)args + * If you want to add an instantiated component_action (or one of its subclasses), use $component->add_action_object($action) + * + * @param string $event a DOM event (click, mouseover etc.) + * @param string $jsfunction The name of the JS function to call + * @param array $jsfunctionargs An optional array of JS arguments to pass to the function + * @return void + */ + public function add_action($event, $jsfunction, $jsfunctionargs=array()) { + while (empty($this->id) || in_array($this->id, moodle_html_component::$generated_ids)) { + $this->generate_id(); + } + $this->actions[] = new component_action($event, $jsfunction, $jsfunctionargs); + } + + /** + * Adds an instantiated component_action to this component. + * Note: the JS function you write must have only two arguments: (string)event and (object|array)args + * + * @param component_action $action An instantiated component_action or one of its subclasses + * @return void + */ + public function add_action_object($action) { + if (!($action instanceof component_action)) { + throw new coding_exception('moodle_html_component::add_action_object($action) only takes an instance of component_action.'); + } + + while (empty($this->id) && !in_array($this->id, moodle_html_component::$generated_ids)) { + $this->generate_id(); + } + $this->actions[] = $action; + } + + /** + * Internal method for generating a unique ID for the purpose of event handlers. + * @return void; + */ + protected function generate_id() { + $this->id = get_class($this) . '-' . substr(sha1(microtime() * rand(0, 500)), 0, 5); + if (!in_array($this->id, moodle_html_component::$generated_ids)) { + moodle_html_component::$generated_ids[] = $this->id; + } + } + + /** + * Returns the array of component_actions. + * @return array Component actions + */ + public function get_actions() { + return $this->actions; + } } @@ -2815,6 +3271,10 @@ class moodle_html_component { * will be printed by {@link moodle_core_renderer::select_menu()}. (Or by an overridden * version of that method in a subclass.) * + * This component can also hold enough metadata to be used as a popup form. It just + * needs a bit more setting up than for a simple menu. See the shortcut methods for + * developer-friendly usage. + * * All the fields that are not set by the constructor have sensible defaults, so * you only need to set the properties where you want non-default behaviour. * @@ -3229,57 +3689,846 @@ class html_table extends moodle_html_component { } } - /** - * A renderer that generates output for command-line scripts. - * - * The implementation of this renderer is probably incomplete. + * Component representing a XHTML link. * - * @copyright 2009 Tim Hunt + * @copyright 2009 Nicolas Connault * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.0 */ -class cli_core_renderer extends moodle_core_renderer { +class html_link extends moodle_html_component { /** - * Returns the page header. - * @return string HTML fragment + * URL can be simple text or a moodle_url object + * @var mixed $url */ - public function header() { - output_starting_hook(); - return $this->page->heading . "\n"; - } + public $url; /** - * Returns a template fragment representing a Heading. - * @param string $text The text of the heading - * @param int $level The level of importance of the heading - * @param string $classes A space-separated list of CSS classes - * @param string $id An optional ID - * @return string A template fragment for a heading + * @var string $text The text that will appear between the link tags */ - public function heading($text, $level, $classes = 'main', $id = '') { - $text .= "\n"; - switch ($level) { - case 1: - return '=>' . $text; - case 2: - return '-->' . $text; - default: - return $text; + public $text; + + /** + * @see lib/moodle_html_component#prepare() + * @return void + */ + public function prepare() { + // We can't accept an empty text value + if (empty($this->text)) { + throw new coding_exception('A html_link must have a descriptive text value!'); } + + parent::prepare(); } +} +/** + * Component representing a help icon. + * + * @copyright 2009 Nicolas Connault + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class help_icon extends moodle_html_component { /** - * Returns a template fragment representing a fatal error. - * @param string $message The message to output - * @param string $moreinfourl URL where more info can be found about the error - * @param string $link Link for the Continue button - * @param array $backtrace The execution backtrace - * @param string $debuginfo Debugging information - * @param bool $showerrordebugwarning Whether or not to show a debugging warning - * @return string A template fragment for a fatal error + * @var html_link $link A html_link object that will hold the URL info */ - public function fatal_error($message, $moreinfourl, $link, $backtrace, + public $link; + /** + * @var string $text A descriptive text + */ + public $text; + /** + * @var string $page The keyword that defines a help page + */ + public $page; + /** + * @var string $module Which module is the page defined in + */ + public $module = 'moodle'; + /** + * @var boolean $linktext Whether or not to show text next to the icon + */ + public $linktext = false; + /** + * @var mixed $image The help icon. Can be set to true (will use default help icon), + * false (will not use any icon), the URL to an image, or a full + * html_image object. + */ + public $image; + + /** + * Constructor: sets up the other components in case they are needed + * @return void + */ + public function __construct() { + $this->link = new html_link(); + $this->image = new html_image(); + } + + /** + * @see lib/moodle_html_component#prepare() + * @return void + */ + public function prepare() { + global $COURSE, $OUTPUT; + + if (empty($this->page)) { + throw new coding_exception('A help_icon object requires a $page parameter'); + } + + if (empty($this->text)) { + throw new coding_exception('A help_icon object requires a $text parameter'); + } + + $this->link->text = $this->text; + + // fix for MDL-7734 + $this->link->url = new moodle_url('/help.php', array('module' => $this->module, 'file' => $this->page .'.html')); + + // fix for MDL-7734 + if (!empty($COURSE->lang)) { + $this->link->url->param('forcelang', $COURSE->lang); + } + + // Catch references to the old text.html and emoticons.html help files that + // were renamed in MDL-13233. + if (in_array($this->page, array('text', 'emoticons', 'richtext'))) { + $oldname = $this->page; + $this->page .= '2'; + debugging("You are referring to the old help file '$oldname'. " . + "This was renamed to '$this->page' because of MDL-13233. " . + "Please update your code.", DEBUG_DEVELOPER); + } + + if ($this->module == '') { + $this->module = 'moodle'; + } + + // Warn users about new window for Accessibility + $this->title = get_string('helpprefix2', '', trim($this->text, ". \t")) .' ('.get_string('newwindow').')'; + + // Prepare image and linktext + if ($this->image && !($this->image instanceof html_image)) { + $image = fullclone($this->image); + $this->image = new html_image(); + + if ($image instanceof moodle_url) { + $this->image->src = $image->out(); + } else if ($image === true) { + $this->image->src = $OUTPUT->old_icon_url('help'); + } else if (is_string($image)) { + $this->image->src = $image; + } + $this->image->alt = $this->text; + + if ($this->linktext) { + $this->image->alt = get_string('helpwiththis'); + } else { + $this->image->alt = $this->title; + } + $this->image->add_class('iconhelp'); + } else if (empty($this->image->src)) { + $this->image->src = $OUTPUT->old_icon_url('help'); + } + + parent::prepare(); + } +} + + +/** + * Component representing a XHTML button (input of type 'button'). + * The renderer will either output it as a button with an onclick event, + * or as a form with hidden inputs. + * + * @copyright 2009 Nicolas Connault + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class html_button extends moodle_html_component { + /** + * @var string $label + */ + public $label; + + /** + * @var boolean $disabled Whether or not this button is disabled + */ + public $disabled = false; + + /** + * @see lib/moodle_html_component#prepare() + * @return void + */ + public function prepare() { + $this->add_class('singlebutton'); + + if (empty($this->label)) { + throw new coding_exception('A html_button must have a label value!'); + } + + if ($this->disabled) { + $this->disabled = 'disabled'; + } + + parent::prepare(); + } +} + +/** + * Component representing an icon linking to a Moodle page. + * + * @copyright 2009 Nicolas Connault + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class action_icon extends moodle_html_component { + /** + * @var string $linktext Optional text to display next to the icon + */ + public $linktext; + /** + * @var html_image $image The icon + */ + public $image; + /** + * @var html_link $link The link + */ + public $link; + + /** + * Constructor: sets up the other components in case they are needed + * @return void + */ + public function __construct() { + $this->image = new html_image(); + $this->link = new html_link(); + } + + /** + * @see lib/moodle_html_component#prepare() + * @return void + */ + public function prepare() { + $this->image->add_class('action-icon'); + + parent::prepare(); + + if (empty($this->image->src)) { + throw new coding_exception('action_icon->image->src must not be empty'); + } + + if (empty($this->image->alt) && !empty($this->linktext)) { + $this->image->alt = $this->linktext; + } else if (empty($this->image->alt)) { + debugging('action_icon->image->alt should not be empty.', DEBUG_DEVELOPER); + } + } +} + +/** + * Component representing an image. + * + * @copyright 2009 Nicolas Connault + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class html_image extends moodle_html_component { + /** + * @var string $alt A descriptive text + */ + public $alt = HTML_ATTR_EMPTY; + /** + * @var string $src The path to the image being used + */ + public $src; + + /** + * @see lib/moodle_html_component#prepare() + * @return void + */ + public function prepare() { + $this->add_class('image'); + parent::prepare(); + } +} + +/** + * Component representing a user picture. + * + * @copyright 2009 Nicolas Connault + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class user_picture extends moodle_html_component { + /** + * @var mixed $user A userid or a user object with at least fields id, picture, imagealrt, firstname and lastname set. + */ + public $user; + /** + * @var int $courseid The course id. Used when constructing the link to the user's profile. + */ + public $courseid; + /** + * @var html_image $image A custom image used as the user picture. + */ + public $image; + /** + * @var mixed $url False: picture not enclosed in a link. True: default link. moodle_url: custom link. + */ + public $url; + /** + * @var int $size Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatibility + */ + public $size; + /** + * @var boolean $alttext add non-blank alt-text to the image. (Default true, set to false for purely + */ + public $alttext = true; + + /** + * Constructor: sets up the other components in case they are needed + * @return void + */ + public function __construct() { + $this->image = new html_image(); + } + + /** + * @see lib/moodle_html_component#prepare() + * @return void + */ + public function prepare() { + global $CFG, $DB, $OUTPUT; + + if (empty($this->user)) { + throw new coding_exception('A user_picture object must have a $user object before being rendered.'); + } + + if (empty($this->courseid)) { + throw new coding_exception('A user_picture object must have a courseid value before being rendered.'); + } + + if (!($this->image instanceof html_image)) { + debugging('user_picture::image must be an instance of html_image', DEBUG_DEVELOPER); + } + + $needrec = false; + // only touch the DB if we are missing data... + if (is_object($this->user)) { + // Note - both picture and imagealt _can_ be empty + // what we are trying to see here is if they have been fetched + // from the DB. We should use isset() _except_ that some installs + // have those fields as nullable, and isset() will return false + // on null. The only safe thing is to ask array_key_exists() + // which works on objects. property_exists() isn't quite + // what we want here... + if (! (array_key_exists('picture', $this->user) + && ($this->alttext && array_key_exists('imagealt', $this->user) + || (isset($this->user->firstname) && isset($this->user->lastname)))) ) { + $needrec = true; + $this->user = $this->user->id; + } + } else { + if ($this->alttext) { + // we need firstname, lastname, imagealt, can't escape... + $needrec = true; + } else { + $userobj = new StdClass; // fake it to save DB traffic + $userobj->id = $user; + $userobj->picture = $picture; + $this->user = clone($userobj); + unset($userobj); + } + } + if ($needrec) { + $this->user = $DB->get_record('user', array('id' => $this->user), 'id,firstname,lastname,imagealt'); + } + + if (!empty($this->link) && empty($this->url)) { + $this->url = new moodle_url('/user/view.php', array('id' => $this->user->id, 'course' => $this->courseid)); + } + + if (empty($this->size)) { + $file = 'f2'; + $this->size = 35; + } else if ($this->size === true or $this->size == 1) { + $file = 'f1'; + $this->size = 100; + } else if ($this->size >= 50) { + $file = 'f1'; + } else { + $file = 'f2'; + } + + $this->add_class('userpicture'); + + if (empty($this->image->src)) { + $this->image->src = $this->user->picture; + } + + if (!empty($this->image->src)) { + require_once($CFG->libdir.'/filelib.php'); + $this->image->src = new moodle_url(get_file_url($this->user->id.'/'.$file.'.jpg', null, 'user')); + } else { // Print default user pictures (use theme version if available) + $this->add_class('defaultuserpic'); + $this->image->src = $OUTPUT->old_icon_url('u/' . $file); + } + + if ($this->alttext) { + if (!empty($this->user->imagealt)) { + $this->image->alt = $this->user->imagealt; + } else { + $this->image->alt = get_string('pictureof','',fullname($this->user)); + } + } + + parent::prepare(); + } +} + +/** + * Component representing a textarea. + * + * @copyright 2009 Nicolas Connault + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class html_textarea extends moodle_html_component { + /** + * @param string $name Name to use for the textarea element. + */ + public $name; + /** + * @param string $value Initial content to display in the textarea. + */ + public $value; + /** + * @param int $rows Number of rows to display (minimum of 10 when $height is non-null) + */ + public $rows; + /** + * @param int $cols Number of columns to display (minimum of 65 when $width is non-null) + */ + public $cols; + /** + * @param bool $usehtmleditor Enables the use of the htmleditor for this field. + */ + public $usehtmleditor; + + /** + * @see lib/moodle_html_component#prepare() + * @return void + */ + public function prepare() { + $this->add_class('form-textarea'); + + if (empty($this->id)) { + $this->id = "edit-$this->name"; + } + + if ($this->usehtmleditor) { + editors_head_setup(); + $editor = get_preferred_texteditor(FORMAT_HTML); + $editor->use_editor($this->id, array('legacy'=>true)); + $this->value = htmlspecialchars($value); + } + + parent::prepare(); + } +} + +/** + * Component representing a simple form wrapper. Its purpose is mainly to enclose + * a submit input with the appropriate action and hidden inputs. + * + * @copyright 2009 Nicolas Connault + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class html_form extends moodle_html_component { + /** + * @var string $method post or get + */ + public $method = 'post'; + /** + * If a string is given, it will be converted to a moodle_url during prepare() + * @var mixed $url A moodle_url including params or a string + */ + public $url; + /** + * @var array $params Optional array of parameters. Ignored if $url instanceof moodle_url + */ + public $params = array(); + /** + * @var boolean $showbutton If true, the submit button will always be shown even if JavaScript is available + */ + public $showbutton = false; + /** + * @var string $targetwindow The name of the target page to open the linked page in. + */ + public $targetwindow = 'self'; + /** + * @var html_button $button A submit button + */ + public $button; + + /** + * Constructor: sets up the other components in case they are needed + * @return void + */ + public function __construct() { + static $go; + $this->button = new html_button(); + if (!isset($go)) { + $go = get_string('go'); + $this->button->label = $go; + } + } + + /** + * @see lib/moodle_html_component#prepare() + * @return void + */ + public function prepare() { + + if (empty($this->url)) { + throw new coding_exception('A html_form must have a $url value (string or moodle_url).'); + } + + if (!($this->url instanceof moodle_url)) { + $this->url = new moodle_url($this->url, $this->params); + } + + if ($this->method == 'post') { + $this->url->param('sesskey', sesskey()); + } + + parent::prepare(); + } +} + +/** + * Component representing a paging bar. + * + * @copyright 2009 Nicolas Connault + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class moodle_paging_bar extends moodle_html_component { + /** + * @var int $maxdisplay The maximum number of pagelinks to display + */ + public $maxdisplay = 18; + /** + * @var int $totalcount post or get + */ + public $totalcount; + /** + * @var int $page The page you are currently viewing + */ + public $page; + /** + * @var int $perpage The number of entries that should be shown per page + */ + public $perpage; + /** + * @var string $baseurl If this is a string then it is the url which will be appended with $pagevar, an equals sign and the page number. + * If this is a moodle_url object then the pagevar param will be replaced by the page no, for each page. + */ + public $baseurl; + /** + * @var string $pagevar This is the variable name that you use for the page number in your code (ie. 'tablepage', 'blogpage', etc) + */ + public $pagevar = 'page'; + /** + * @var bool $nocurr do not display the current page as a link + */ + public $nocurr; + /** + * @var html_link $previouslink A HTML link representing the "previous" page + */ + public $previouslink = null; + /** + * @var html_link $nextlink A HTML link representing the "next" page + */ + public $nextlink = null; + /** + * @var html_link $firstlink A HTML link representing the first page + */ + public $firstlink = null; + /** + * @var html_link $lastlink A HTML link representing the last page + */ + public $lastlink = null; + /** + * @var array $pagelinks An array of html_links. One of them is just a string: the current page + */ + public $pagelinks = array(); + + /** + * @see lib/moodle_html_component#prepare() + * @return void + */ + public function prepare() { + if (!($this->baseurl instanceof moodle_url)) { + $this->baseurl = new moodle_url($this->baseurl); + } + + if ($this->totalcount > $this->perpage) { + $pagenum = $this->page - 1; + + if ($this->page > 0) { + $this->previouslink = new html_link(); + $this->previouslink->add_class('previous'); + $this->previouslink->url = $this->baseurl->out(false, array($this->pagevar => $pagenum)); + $this->previouslink->text = get_string('previous'); + } + + if ($this->perpage > 0) { + $lastpage = ceil($this->totalcount / $this->perpage); + } else { + $lastpage = 1; + } + + if ($this->page > 15) { + $startpage = $this->page - 10; + + $this->firstlink = new html_link(); + $this->firstlink->url = $this->baseurl->out(false, array($this->pagevar => 0)); + $this->firstlink->text = 1; + $this->firstlink->add_class('first'); + } else { + $startpage = 0; + } + + $currpage = $startpage; + $displaycount = $displaypage = 0; + + while ($displaycount < $this->maxdisplay and $currpage < $lastpage) { + $displaypage = $currpage + 1; + + if ($this->page == $currpage && empty($this->nocurr)) { + $this->pagelinks[] = $displaypage; + } else { + $pagelink = new html_link(); + $pagelink->url = $this->baseurl->out(false, array($this->pagevar => $currpage)); + $pagelink->text = $displaypage; + $this->pagelinks[] = $pagelink; + } + + $displaycount++; + $currpage++; + } + + if ($currpage < $lastpage) { + $lastpageactual = $lastpage - 1; + $this->lastlink = new html_link(); + $this->lastlink->url = $this->baseurl->out(false, array($this->pagevar => $lastpageactual)); + $this->lastlink->text = $lastpage; + $this->lastlink->add_class('last'); + } + + $pagenum = $this->page + 1; + + if ($pagenum != $displaypage) { + $this->nextlink = new html_link(); + $this->nextlink->url = $this->baseurl->out(false, array($this->pagevar => $pagenum)); + $this->nextlink->text = get_string('next'); + $this->nextlink->add_class('next'); + } + } + } + +} + +/// ACTIONS + +/** + * Helper class used by other components that involve an action on the page (URL or JS). + * + * @copyright 2009 Nicolas Connault + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class component_action { + + /** + * The DOM event that will trigger this action when caught + * @var string $event DOM event + */ + public $event; + + /** + * The JS function you create must have two arguments: + * 1. The event object + * 2. An object/array of arguments ($jsfunctionargs) + * @var string $jsfunction A function name to call when the button is clicked + */ + public $jsfunction = false; + + /** + * @var array $jsfunctionargs An array of arguments to pass to the JS function + */ + public $jsfunctionargs = array(); + + /** + * Constructor + * @param string $event DOM event + * @param moodle_url $url A moodle_url object, required if no jsfunction is given + * @param string $method 'post' or 'get' + * @param string $jsfunction An optional JS function. Required if jsfunctionargs is given + * @param array $jsfunctionargs An array of arguments to pass to the jsfunction + * @return void + */ + public function __construct($event, $jsfunction, $jsfunctionargs=array()) { + $this->event = $event; + + $this->jsfunction = $jsfunction; + $this->jsfunctionargs = $jsfunctionargs; + + if (!empty($this->jsfunctionargs)) { + if (empty($this->jsfunction)) { + throw new coding_exception('The component_action object needs a jsfunction value to pass the jsfunctionargs to.'); + } + } + } +} + +/** + * Component action for a popup window. + * + * @copyright 2009 Nicolas Connault + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class popup_action extends component_action { + /** + * @var array $params An array of parameters that will be passed to the openpopup JS function + */ + public $params = array( + 'height' => 400, + 'width' => 500, + 'top' => 0, + 'left' => 0, + 'menubar' => false, + 'location' => false, + 'scrollbars' => true, + 'resizable' => true, + 'toolbar' => true, + 'status' => true, + 'directories' => false, + 'fullscreen' => false, + 'dependent' => true); + + /** + * Constructor + * @param string $event DOM event + * @param moodle_url $url A moodle_url object, required if no jsfunction is given + * @param string $method 'post' or 'get' + * @param array $params An array of popup parameters + * @return void + */ + public function __construct($event, $url, $name='popup', $params=array()) { + global $CFG; + $this->name = $name; + + $url = new moodle_url($url); + + if ($this->name) { + $_name = $this->name; + if (($_name = preg_replace("/\s/", '_', $_name)) != $this->name) { + throw new coding_exception('The $name of a popup window shouldn\'t contain spaces - string modified. '. $this->name .' changed to '. $_name); + $this->name = $_name; + } + } else { + $this->name = 'popup'; + } + + foreach ($this->params as $var => $val) { + if (array_key_exists($var, $params)) { + $this->params[$var] = $params[$var]; + } + } + parent::__construct($event, 'openpopup', array('url' => $url->out(false, array(), false), 'name' => $name, 'options' => $this->get_js_options($params))); + } + + /** + * Returns a string of concatenated option->value pairs used by JS to call the popup window, + * based on this object's variables + * + * @return string String of option->value pairs for JS popup function. + */ + public function get_js_options() { + $jsoptions = ''; + + foreach ($this->params as $var => $val) { + if (is_string($val) || is_int($val)) { + $jsoptions .= "$var=$val,"; + } elseif (is_bool($val)) { + $jsoptions .= ($val) ? "$var," : "$var=0,"; + } + } + + $jsoptions = substr($jsoptions, 0, strlen($jsoptions) - 1); + + return $jsoptions; + } +} + +/// RENDERERS + +/** + * A renderer that generates output for command-line scripts. + * + * The implementation of this renderer is probably incomplete. + * + * @copyright 2009 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.0 + */ +class cli_core_renderer extends moodle_core_renderer { + /** + * Returns the page header. + * @return string HTML fragment + */ + public function header() { + output_starting_hook(); + return $this->page->heading . "\n"; + } + + /** + * Returns a template fragment representing a Heading. + * @param string $text The text of the heading + * @param int $level The level of importance of the heading + * @param string $classes A space-separated list of CSS classes + * @param string $id An optional ID + * @return string A template fragment for a heading + */ + public function heading($text, $level, $classes = 'main', $id = '') { + $text .= "\n"; + switch ($level) { + case 1: + return '=>' . $text; + case 2: + return '-->' . $text; + default: + return $text; + } + } + + /** + * Returns a template fragment representing a fatal error. + * @param string $message The message to output + * @param string $moreinfourl URL where more info can be found about the error + * @param string $link Link for the Continue button + * @param array $backtrace The execution backtrace + * @param string $debuginfo Debugging information + * @param bool $showerrordebugwarning Whether or not to show a debugging warning + * @return string A template fragment for a fatal error + */ + public function fatal_error($message, $moreinfourl, $link, $backtrace, $debuginfo = null, $showerrordebugwarning = false) { $output = "!!! $message !!!\n"; @@ -3423,3 +4672,23 @@ function output_css_for_css_edit($files, $toreplace) { echo "/* @end */\n\n"; } } + +/** + * Given a moodle_html_component with height and/or width set, translates them + * to appropriate CSS rules. + * + * @param moodle_html_component $component + * @return string CSS rules + */ +function prepare_legacy_width_and_height($component) { + $output = ''; + if (!empty($component->height)) { + debugging('Explicit height given to moodle_html_component leads to inline css. Use a proper CSS class instead.', DEBUG_DEVELOPER); + $output = "height: {$component->height}px;"; + } + if (!empty($component->width)) { + debugging('Explicit width given to moodle_html_component leads to inline css. Use a proper CSS class instead.', DEBUG_DEVELOPER); + $output .= "width: {$component->width}px;"; + } + return $output; +} diff --git a/lib/simpletest/testdeprecatedlib.php b/lib/simpletest/testdeprecatedlib.php new file mode 100644 index 0000000000..76257caf76 --- /dev/null +++ b/lib/simpletest/testdeprecatedlib.php @@ -0,0 +1,74 @@ +. + + +/** + * Unit tests for ../deprecatedlib.php. + * + * @package moodlecore + * @copyright 2009 Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later (5) + */ + +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page +} +require_once($CFG->libdir . '/deprecatedlib.php'); + +class outputlib_methods_test extends UnitTestCase { + public function test_print_single_button() { + global $PAGE, $CFG; + + // Basic params, absolute URL + $link = 'http://www.test.com/index.php'; + $options = array('param1' => 'value1'); + $label = 'OK'; + $method = 'get'; + $return = true; + $tooltip = ''; + $disabled = false; + $jsconfirmmessage = ''; + $formid = ''; + + $html = print_single_button($link, $options, $label, $method, '', $return, $tooltip, $disabled, $jsconfirmmessage, $formid); + $this->assert(new ContainsTagWithAttributes('form', array('method' => $method, 'action' => $link)), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'param1', 'value' => 'value1')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => 'OK')), $html); + + // URL with & params + $newlink = $link . '?param1=value1&param2=value2'; + $html = print_single_button($newlink, $options, $label, $method, '', $return, $tooltip, $disabled, $jsconfirmmessage, $formid); + $this->assert(new ContainsTagWithAttributes('form', array('method' => $method, 'action' => $link)), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'param1', 'value' => 'value1')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => 'OK')), $html); + + // URL with & params + $newlink = $link . '?param1=value1¶m2=value2'; + $html = print_single_button($newlink, $options, $label, $method, '', $return, $tooltip, $disabled, $jsconfirmmessage, $formid); + $this->assert(new ContainsTagWithAttributes('form', array('method' => $method, 'action' => $link)), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'param1', 'value' => 'value1')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => 'OK')), $html); + + // relative URL with & params + $newlink = 'index.php?param1=value1¶m2=value2'; + $PAGE->set_url('index.php'); + $html = print_single_button($newlink, $options, $label, $method, '', $return, $tooltip, $disabled, $jsconfirmmessage, $formid); + $this->assert(new ContainsTagWithAttributes('form', array('method' => $method, 'action' => $CFG->wwwroot . '/index.php')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'param1', 'value' => 'value1')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => 'OK')), $html); + } +} diff --git a/lib/simpletest/testoutputlib.php b/lib/simpletest/testoutputlib.php index 28ff563ba7..3e659fc548 100644 --- a/lib/simpletest/testoutputlib.php +++ b/lib/simpletest/testoutputlib.php @@ -578,7 +578,7 @@ class template_renderer_factory_test extends UnitTestCase { $this->make_theme_template_dir('mytheme'); $this->make_theme_template_dir('parenttheme'); $this->make_theme_template_dir('standardtemplate'); - + // Exercise SUT. $factory = new testable_template_renderer_factory($theme, $this->page); @@ -597,7 +597,7 @@ class template_renderer_factory_test extends UnitTestCase { $theme->parent = 'parenttheme'; $this->make_theme_template_dir('mytheme'); $this->make_theme_template_dir('standardtemplate'); - + // Exercise SUT. $factory = new testable_template_renderer_factory($theme, $this->page); $subfactory = new testable_template_renderer_factory($theme, $this->page, 'subtype'); @@ -905,4 +905,252 @@ class moodle_core_renderer_test extends UnitTestCase { $html = $this->renderer->error_text(''); $this->assertEqual('', $html); } + + public function test_link_to_popup_empty_link() { + // Empty link object: link MUST have a text value + $link = new html_link(); + $popupaction = new popup_action('click', 'http://test.com', 'my_popup'); + $link->add_action_object($popupaction); + $this->expectException(); + $html = $this->renderer->link_to_popup($link); + } + + public function test_link_to_popup() { + $link = new html_link(); + $link->text = 'Click here'; + $link->url = 'http://test.com'; + $link->title = 'Popup window'; + $popupaction = new popup_action('click', 'http://test.com', 'my_popup'); + $link->add_action_object($popupaction); + + $html = $this->renderer->link_to_popup($link); + $expectedattributes = array('title' => 'Popup window', 'href' => 'http://test.com'); + $this->assert(new ContainsTagWithAttributes('a', $expectedattributes), $html); + $this->assert(new ContainsTagWithContents('a', 'Click here'), $html); + + // Try a different url for the link than for the popup + $link->url = 'http://otheraddress.com'; + $html = $this->renderer->link_to_popup($link); + + $this->assert(new ContainsTagWithAttribute('a', 'title', 'Popup window'), $html); + $this->assert(new ContainsTagWithAttribute('a', 'href', 'http://otheraddress.com'), $html); + $this->assert(new ContainsTagWithContents('a', 'Click here'), $html); + + // Give it a moodle_url object instead of a string + $link->url = new moodle_url('http://otheraddress.com'); + $html = $this->renderer->link_to_popup($link); + $this->assert(new ContainsTagWithAttribute('a', 'title', 'Popup window'), $html); + $this->assert(new ContainsTagWithAttribute('a', 'href', 'http://otheraddress.com'), $html); + $this->assert(new ContainsTagWithContents('a', 'Click here'), $html); + + } + + public function test_button() { + global $CFG; + $originalform = new html_form(); + $originalform->button->label = 'Click Here'; + $originalform->url = '/index.php'; + + $form = clone($originalform); + + $html = $this->renderer->button($form); + $this->assert(new ContainsTagWithAttribute('div', 'class', 'singlebutton'), $html); + $this->assert(new ContainsTagWithAttributes('form', array('method' => 'post', 'action' => $CFG->wwwroot . '/index.php')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())), $html); + $this->assert(new ContainsTagWithAttributes('input', array('value' => 'Click Here', 'type' => 'submit')), $html); + + $form = clone($originalform); + $form->button->confirmmessage = 'Are you sure?'; + + $html = $this->renderer->button($form); + $this->assert(new ContainsTagWithAttribute('div', 'class', 'singlebutton'), $html); + $this->assert(new ContainsTagWithAttributes('form', array('method' => 'post', 'action' => $CFG->wwwroot . '/index.php')), $html); + $this->assert(new ContainsTagWithAttribute('input', 'type', 'submit'), $html); + + $form = clone($originalform); + $form->url = new moodle_url($form->url, array('var1' => 'value1', 'var2' => 'value2')); + $html = $this->renderer->button($form); + $this->assert(new ContainsTagWithAttributes('input', array('name' => 'var1', 'type' => 'hidden', 'value' => 'value1')), $html); + + } + + public function test_link() { + $link = new html_link(); + $link->url = 'http://test.com'; + $link->text = 'Resource 1'; + + $html = $this->renderer->link($link); + $this->assert(new ContainsTagWithAttribute('a', 'href', 'http://test.com'), $html); + $this->assert(new ContainsTagWithContents('a', 'Resource 1'), $html); + + // Add a title + $link->title = 'Link to resource 1'; + $html = $this->renderer->link($link); + $this->assert(new ContainsTagWithAttributes('a', array('title' => 'Link to resource 1', 'href' => 'http://test.com')), $html); + $this->assert(new ContainsTagWithContents('a', 'Resource 1'), $html); + + // Use a moodle_url object instead of string + $link->url = new moodle_url($link->url); + $html = $this->renderer->link($link); + $this->assert(new ContainsTagWithAttributes('a', array('title' => 'Link to resource 1', 'href' => 'http://test.com')), $html); + $this->assert(new ContainsTagWithContents('a', 'Resource 1'), $html); + + // Add a few classes to the link object + $link->add_classes('cool blue'); + $html = $this->renderer->link($link); + $this->assert(new ContainsTagWithAttributes('a', array('title' => 'Link to resource 1', 'class' => 'link cool blue', 'href' => 'http://test.com')), $html); + $this->assert(new ContainsTagWithContents('a', 'Resource 1'), $html); + + // Simple use of link() without a html_link object + $html = $this->renderer->link($link->url->out(), $link->text); + $expected_html = '
Resource 1'; + $this->assert(new ContainsTagWithAttribute('a', 'href', 'http://test.com'), $html); + $this->assert(new ContainsTagWithContents('a', 'Resource 1'), $html); + + // Missing second param when first is a string: exception + $this->expectException(); + $html = $this->renderer->link($link->url->out()); + } + + /** + * NOTE: consider the degree of detail in which we test HTML output, because + * the unit tests may be run under a different theme, with different HTML + * renderers. Maybe we should limit unit tests to standardwhite. + */ + public function test_confirm() { + // Basic test with string URLs + $continueurl = 'http://www.test.com/index.php?continue=1'; + $cancelurl = 'http://www.test.com/index.php?cancel=1'; + $message = 'Are you sure?'; + + $html = $this->renderer->confirm($message, $continueurl, $cancelurl); + $this->assert(new ContainsTagWithAttributes('div', array('id' => 'notice', 'class' => 'box generalbox')), $html); + $this->assert(new ContainsTagWithContents('p', $message), $html); + $this->assert(new ContainsTagWithAttribute('div', 'class', 'buttons'), $html); + $this->assert(new ContainsTagWithAttribute('div', 'class', 'singlebutton'), $html); + $this->assert(new ContainsTagWithAttributes('form', array('method' => 'post', 'action' => 'http://www.test.com/index.php')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'continue', 'value' => 1)), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => get_string('yes'), 'class' => 'singlebutton')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'cancel', 'value' => 1)), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => get_string('no'), 'class' => 'singlebutton')), $html); + + // Use html_forms with default values, should produce exactly the same output as above + $formcontinue = new html_form(); + $formcancel = new html_form(); + $formcontinue->url = new moodle_url($continueurl); + $formcancel->url = new moodle_url($cancelurl); + $html = $this->renderer->confirm($message, $formcontinue, $formcancel); + $this->assert(new ContainsTagWithAttributes('div', array('id' => 'notice', 'class' => 'box generalbox')), $html); + $this->assert(new ContainsTagWithContents('p', $message), $html); + $this->assert(new ContainsTagWithAttribute('div', 'class', 'buttons'), $html); + $this->assert(new ContainsTagWithAttribute('div', 'class', 'singlebutton'), $html); + $this->assert(new ContainsTagWithAttributes('form', array('method' => 'post', 'action' => 'http://www.test.com/index.php')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'continue', 'value' => 1)), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => get_string('yes'), 'class' => 'singlebutton')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'cancel', 'value' => 1)), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => get_string('no'), 'class' => 'singlebutton')), $html); + + // Give the buttons some different labels + $formcontinue = new html_form(); + $formcancel = new html_form(); + $formcontinue->url = new moodle_url($continueurl); + $formcancel->url = new moodle_url($cancelurl); + $formcontinue->button->label = 'Continue anyway'; + $formcancel->button->label = 'Wow OK, I get it, backing out!'; + $html = $this->renderer->confirm($message, $formcontinue, $formcancel); + $this->assert(new ContainsTagWithAttributes('form', array('method' => 'post', 'action' => 'http://www.test.com/index.php')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'continue', 'value' => 1)), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => $formcontinue->button->label, 'class' => 'singlebutton')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'cancel', 'value' => 1)), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => $formcancel->button->label, 'class' => 'singlebutton')), $html); + + // Change the method and add extra variables + $formcontinue = new html_form(); + $formcancel = new html_form(); + $formcontinue->url = new moodle_url($continueurl, array('var1' => 'val1', 'var2' => 'val2')); + $formcancel->url = new moodle_url($cancelurl, array('var3' => 'val3', 'var4' => 'val4')); + $html = $this->renderer->confirm($message, $formcontinue, $formcancel); + $this->assert(new ContainsTagWithAttributes('form', array('method' => 'post', 'action' => 'http://www.test.com/index.php')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'continue', 'value' => 1)), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'var1', 'value' => 'val1')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'var2', 'value' => 'val2')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => get_string('yes'), 'class' => 'singlebutton')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'cancel', 'value' => 1)), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'submit', 'value' => get_string('no'), 'class' => 'singlebutton')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'var3', 'value' => 'val3')), $html); + $this->assert(new ContainsTagWithAttributes('input', array('type' => 'hidden', 'name' => 'var4', 'value' => 'val4')), $html); + + } + + public function test_spacer() { + global $CFG; + + $spacer = new html_image(); + + $html = $this->renderer->spacer($spacer); + $this->assert(new ContainsTagWithAttributes('img', array('class' => 'image spacer', + 'src' => $CFG->wwwroot . '/pix/spacer.gif', + 'alt' => '' + )), $html); + $spacer = new html_image(); + $spacer->src = $this->renderer->old_icon_url('myspacer'); + $spacer->alt = 'sometext'; + $spacer->add_class('my'); + + $html = $this->renderer->spacer($spacer); + + $this->assert(new ContainsTagWithAttributes('img', array( + 'class' => 'my image spacer', + 'src' => $this->renderer->old_icon_url('myspacer'), + 'alt' => 'sometext')), $html); + + } + + public function test_paging_bar() { + global $CFG, $OUTPUT; + + $totalcount = 5; + $perpage = 4; + $page = 1; + $baseurl = new moodle_url($CFG->wwwroot.'/index.php'); + $pagevar = 'mypage'; + + $pagingbar = new moodle_paging_bar(); + $pagingbar->totalcount = $totalcount; + $pagingbar->page = $page; + $pagingbar->perpage = $perpage; + $pagingbar->baseurl = $baseurl; + $pagingbar->pagevar = $pagevar; + $pagingbar->nocurr = true; + + $originalbar = clone($pagingbar); + + $html = $OUTPUT->paging_bar($pagingbar); + + $this->assert(new ContainsTagWithAttribute('div', 'class', 'paging'), $html); + $this->assert(new ContainsTagWithAttributes('a', array('class' => 'previous', 'href' => $baseurl->out().'?mypage=0')), $html); + // One of the links to the previous page must not have the 'previous' class + $this->assert(new ContainsTagWithAttributes('a', array('href' => $baseurl->out().'?mypage=0'), array('class' => 'previous')), $html); + // The link to the current page must not have the 'next' class: it's the last page + $this->assert(new ContainsTagWithAttributes('a', array('href' => $baseurl->out().'?mypage=1'), array('class' => 'next')), $html); + + $pagingbar = clone($originalbar); // clone the original bar before each output and set of assertions + $pagingbar->nocurr = false; + $html = $OUTPUT->paging_bar($pagingbar); + $this->assert(new ContainsTagWithAttribute('div', 'class', 'paging'), $html); + $this->assert(new ContainsTagWithAttributes('a', array('href' => $baseurl->out().'?mypage=0'), array('class' => 'previous')), $html); + $this->assert(new ContainsTagWithAttributes('a', array('class' => 'previous', 'href' => $baseurl->out().'?mypage=0')), $html); + $expectation = new ContainsTagWithAttributes('a', array('href' => $baseurl->out().'?mypage=1'), array('class' => 'next')); + $this->assertFalse($expectation->test($html)); + + // TODO test with more different parameters + } } diff --git a/lib/simpletest/testweblib.php b/lib/simpletest/testweblib.php index d75a943bb8..24c41a8faf 100644 --- a/lib/simpletest/testweblib.php +++ b/lib/simpletest/testweblib.php @@ -70,7 +70,7 @@ class web_test extends UnitTestCase { $this->assertEqual(highlight('good', 'This is goodness'), 'This is goodness'); } - function test_replace_ampersands() { + function test_replace_ampersands() { $this->assertEqual(replace_ampersands_not_followed_by_entity("This & that  "), "This & that  "); $this->assertEqual(replace_ampersands_not_followed_by_entity("This   that  "), "This &nbsp that  "); } @@ -92,10 +92,29 @@ class web_test extends UnitTestCase { $string = "visit http://www.moodle.org"; convert_urls_into_links($string); $this->assertEqual($string, 'visit http://www.moodle.org'); - + $string = "visit www.moodle.org"; convert_urls_into_links($string); $this->assertEqual($string, 'visit www.moodle.org'); } + + function test_prepare_url() { + global $CFG, $PAGE; + $fullexternalurl = 'http://www.externalsite.com/somepage.php'; + $fullmoodleurl = $CFG->wwwroot . '/mod/forum/view.php?id=5'; + $relativeurl1 = 'edit.php'; + $relativeurl2 = '/edit.php'; + + $this->assertEqual($fullmoodleurl, prepare_url($fullmoodleurl)); + $this->assertEqual($fullexternalurl, prepare_url($fullexternalurl)); + $this->assertEqual("$CFG->wwwroot/admin/report/unittest/$relativeurl1", prepare_url($relativeurl1)); + $this->assertEqual("$CFG->wwwroot$relativeurl2", prepare_url($relativeurl2)); + + // Use moodle_url object + $this->assertEqual($fullmoodleurl, prepare_url(new moodle_url('/mod/forum/view.php', array('id' => 5)))); + $this->assertEqual($fullexternalurl, prepare_url(new moodle_url($fullexternalurl))); + $this->assertEqual("$CFG->wwwroot/admin/report/unittest/$relativeurl1", prepare_url(new moodle_url($relativeurl1))); + $this->assertEqual("$CFG->wwwroot$relativeurl2", prepare_url(new moodle_url($relativeurl2))); + } } ?> diff --git a/lib/simpletestlib.php b/lib/simpletestlib.php index adefa18bf9..ae085d00fc 100644 --- a/lib/simpletestlib.php +++ b/lib/simpletestlib.php @@ -229,59 +229,96 @@ class ContainsTagWithAttribute extends SimpleExpectation { /** * An Expectation that looks to see whether some HMTL contains a tag with an array of attributes. * All attributes must be present and their values must match the expected values. + * A third parameter can be used to specify attribute=>value pairs which must not be present in a positive match. * * @copyright 2009 Nicolas Connault * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class ContainsTagWithAttributes extends SimpleExpectation { + /** + * @var string $tag The name of the Tag to search + */ protected $tag; - protected $attributes = array(); + /** + * @var array $expectedvalues An associative array of parameters, all of which must be matched + */ + protected $expectedvalues = array(); + /** + * @var array $forbiddenvalues An associative array of parameters, none of which must be matched + */ + protected $forbiddenvalues = array(); + /** + * @var string $failurereason The reason why the test failed: nomatch or forbiddenmatch + */ + protected $failurereason = 'nomatch'; - function __construct($tag, $attributes, $message = '%s') { + function __construct($tag, $expectedvalues, $forbiddenvalues=array(), $message = '%s') { $this->SimpleExpectation($message); $this->tag = $tag; - $this->attributes = $attributes; + $this->expectedvalues = $expectedvalues; + $this->forbiddenvalues = $forbiddenvalues; } - + function test($html) { $parser = new DOMDocument(); $parser->validateOnParse = true; $parser->loadHTML($html); $list = $parser->getElementsByTagName($this->tag); - + + $foundamatch = false; + // Iterating through inputs foreach ($list as $node) { if (empty($node->attributes) || !is_a($node->attributes, 'DOMNamedNodeMap')) { continue; } - $result = true; + // For the current expected attribute under consideration, check that values match + $allattributesmatch = true; - foreach ($this->attributes as $attribute => $expectedvalue) { - if (!$node->attributes->getNamedItem($attribute)) { - break 2; + foreach ($this->expectedvalues as $expectedattribute => $expectedvalue) { + if (!$node->getAttribute($expectedattribute)) { + $this->failurereason = 'nomatch'; + continue 2; // Skip this tag, it doesn't have all the expected attributes } - - if ($node->attributes->getNamedItem($attribute)->value != $expectedvalue) { - $result = false; + if ($node->getAttribute($expectedattribute) != $expectedvalue) { + $allattributesmatch = false; + $this->failurereason = 'nomatch'; } } - if ($result) { - return true; + if ($allattributesmatch) { + $foundamatch = true; + + // Now make sure this node doesn't have any of the forbidden attributes either + $nodeattrlist = $node->attributes; + + foreach ($nodeattrlist as $domattrname => $domattr) { + if (array_key_exists($domattrname, $this->forbiddenvalues) && $node->getAttribute($domattrname) == $this->forbiddenvalues[$domattrname]) { + $this->failurereason = "forbiddenmatch:$domattrname:" . $node->getAttribute($domattrname); + $foundamatch = false; + } + } } - } - return false; + + return $foundamatch; } - + function testMessage($html) { - $output = 'Content [' . $html . '] does not contain the tag [' . $this->tag . '] with attributes ['; - foreach ($this->attributes as $var => $val) { - $output .= "$var=\"$val\" "; + $output = 'Content [' . $html . '] '; + + if (preg_match('/forbiddenmatch:(.*):(.*)/', $this->failurereason, $matches)) { + $output .= "contains the tag $this->tag with the forbidden attribute=>value pair: [$matches[1]=>$matches[2]]"; + } else if ($this->failurereason == 'nomatch') { + $output .= 'does not contain the tag [' . $this->tag . '] with attributes ['; + foreach ($this->expectedvalues as $var => $val) { + $output .= "$var=\"$val\" "; + } + $output = rtrim($output); + $output .= '].'; } - $output = rtrim($output); - $output .= ']'; + return $output; } } diff --git a/lib/weblib.php b/lib/weblib.php index e4d57b34db..50b910ac17 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -318,7 +318,7 @@ class moodle_url { * * The added params override existing ones if they have the same name. * - * @param array $params Defaults to null. If null then return value of param 'name'. + * @param array $params Defaults to null. If null then returns all params. * @return array Array of Params for url. */ public function params($params = null) { @@ -483,6 +483,41 @@ class moodle_url { } } +/** + * Given an unknown $url type (string or moodle_url), returns a string URL. + * A relative URL is handled with $PAGE->url but gives a debugging error. + * + * @param mixed $url The URL (moodle_url or string) + * @param bool $stripformparams Whether or not to strip the query params from the URL + * @return string + */ +function prepare_url($url, $stripformparams=false) { + global $CFG, $PAGE; + + $output = $url; + + if ($url instanceof moodle_url) { + $output = $url->out($stripformparams); + } + + // Handle relative URLs + if (substr($output, 0, 4) != 'http' && substr($output, 0, 1) != '/') { + if (preg_match('/(.*)\/([A-Za-z0-9-_]*\.php)$/', $PAGE->url->out(true), $matches)) { + debugging('Relative URLs are deprecated, please use an absolute URL in your code', DEBUG_DEVELOPER); + return $matches[1] . "/$output"; + } else { + throw new coding_exception('Your page uses bizarre relative URLs which Moodle cannot handle. Please use absolute URLs.'); + } + } + + // Add wwwroot only if the URL does not already start with http:// or https:// + if (!preg_match('|https?://|', $output) ) { + $output = $CFG->wwwroot . $output; + } + + return $output; +} + /** * Determine if there is data waiting to be processed from a form * @@ -552,157 +587,6 @@ function break_up_long_words($string, $maxsize=20, $cutchar=' ') { return $output; } -/** - * This function will print a button/link/etc. form element - * that will work on both Javascript and non-javascript browsers. - * - * Relies on the Javascript function openpopup in javascript.php - * All parameters default to null, only $type and $url are mandatory. - * - * $url must be relative to home page eg /mod/survey/stuff.php - * - * @global object - * @param string $type Can be 'button' or 'link' - * @param string $url Web link. Either relative to $CFG->wwwroot, or a full URL. - * @param string $name Name to be assigned to the popup window (this is used by - * client-side scripts to "talk" to the popup window) - * @param string $linkname Text to be displayed as web link - * @param int $height Height to assign to popup window - * @param int $width Height to assign to popup window - * @param string $title Text to be displayed as popup page title - * @param string $options List of additional options for popup window - * @param bool $return If true, return as a string, otherwise print - * @param string $id id added to the element - * @param string $class class added to the element - * @return string - */ -function element_to_popup_window ($type=null, $url=null, $name=null, $linkname=null, - $height=400, $width=500, $title=null, - $options=null, $return=false, $id=null, $class=null) { - - if (is_null($url)) { - debugging('You must give the url to display in the popup. URL is missing - can\'t create popup window.', DEBUG_DEVELOPER); - } - - global $CFG; - - if ($options == 'none') { // 'none' is legacy, should be removed in v2.0 - $options = null; - } - - // add some sane default options for popup windows - if (!$options) { - $options = 'menubar=0,location=0,scrollbars,resizable'; - } - if ($width) { - $options .= ',width='. $width; - } - if ($height) { - $options .= ',height='. $height; - } - if ($id) { - $id = ' id="'.$id.'" '; - } - if ($class) { - $class = ' class="'.$class.'" '; - } - if ($name) { - $_name = $name; - if (($name = preg_replace("/\s/", '_', $name)) != $_name) { - debugging('The $name of a popup window shouldn\'t contain spaces - string modified. '. $_name .' changed to '. $name, DEBUG_DEVELOPER); - } - } else { - $name = 'popup'; - } - - // get some default string, using the localized version of legacy defaults - if (is_null($linkname) || $linkname === '') { - $linkname = get_string('clickhere'); - } - if (!$title) { - $title = get_string('popupwindowname'); - } - - $fullscreen = 0; // must be passed to openpopup - $element = ''; - - switch ($type) { - case 'button': - $element = '\n"; - break; - case 'link': - // Add wwwroot only if the URL does not already start with http:// or https:// - if (!preg_match('|https?://|', $url)) { - $url = $CFG->wwwroot . $url; - } - $element = '$linkname"; - break; - default : - print_error('cannotcreatepopupwin'); - break; - } - - if ($return) { - return $element; - } else { - echo $element; - } -} - -/** - * Creates and displays (or returns) a link to a popup window, using element_to_popup_window function. - * - * Simply calls {@link element_to_popup_window()} with type set to 'link' - * @see element_to_popup_window() - * - * @param string $url Web link. Either relative to $CFG->wwwroot, or a full URL. - * @param string $name Name to be assigned to the popup window (this is used by - * client-side scripts to "talk" to the popup window) - * @param string $linkname Text to be displayed as web link - * @param int $height Height to assign to popup window - * @param int $width Height to assign to popup window - * @param string $title Text to be displayed as popup page title - * @param string $options List of additional options for popup window - * @param bool $return If true, return as a string, otherwise print - * @param string $id id added to the element - * @param string $class class added to the element - * @return string html code to display a link to a popup window. - */ -function link_to_popup_window ($url, $name=null, $linkname=null, - $height=400, $width=500, $title=null, - $options=null, $return=false) { - - return element_to_popup_window('link', $url, $name, $linkname, $height, $width, $title, $options, $return, null, null); -} - -/** - * Creates and displays (or returns) a buttons to a popup window, using element_to_popup_window function. - * - * Simply calls {@link element_to_popup_window()} with type set to 'button' - * @see element_to_popup_window() - * - * @param string $url Web link. Either relative to $CFG->wwwroot, or a full URL. - * @param string $name Name to be assigned to the popup window (this is used by - * client-side scripts to "talk" to the popup window) - * @param string $linkname Text to be displayed as web link - * @param int $height Height to assign to popup window - * @param int $width Height to assign to popup window - * @param string $title Text to be displayed as popup page title - * @param string $options List of additional options for popup window - * @param bool $return If true, return as a string, otherwise print - * @param string $id id added to the element - * @param string $class class added to the element - * @return string html code to display a link to a popup window. - */ -function button_to_popup_window ($url, $name=null, $linkname=null, - $height=400, $width=500, $title=null, $options=null, $return=false, - $id=null, $class=null) { - - return element_to_popup_window('button', $url, $name, $linkname, $height, $width, $title, $options, $return, $id, $class); -} - /** * Prints a simple button to close a window @@ -3164,240 +3048,6 @@ function _print_custom_corners_end($idbase) { } -/** - * Print a self contained form with a single submit button. - * - * @param string $link used as the action attribute on the form, so the URL that will be hit if the button is clicked. - * @param array $options these become hidden form fields, so these options get passed to the script at $link. - * @param string $label the caption that appears on the button. - * @param string $method HTTP method used on the request of the button is clicked. 'get' or 'post'. - * @param string $notusedanymore no longer used. - * @param boolean $return if false, output the form directly, otherwise return the HTML as a string. - * @param string $tooltip a tooltip to add to the button as a title attribute. - * @param boolean $disabled if true, the button will be disabled. - * @param string $jsconfirmmessage if not empty then display a confirm dialogue with this string as the question. - * @param string $formid The id attribute to use for the form - * @return string|void Depending on the $return paramter. - */ -function print_single_button($link, $options, $label='OK', $method='get', $notusedanymore='', - $return=false, $tooltip='', $disabled = false, $jsconfirmmessage='', $formid = '') { - $output = ''; - if ($formid) { - $formid = ' id="' . s($formid) . '"'; - } - $link = str_replace('"', '"', $link); //basic XSS protection - $output .= '
'; - // taking target out, will need to add later target="'.$target.'" - $output .= '
'; - $output .= '
'; - if ($options) { - foreach ($options as $name => $value) { - $output .= ''; - } - } - if ($tooltip) { - $tooltip = 'title="' . s($tooltip) . '"'; - } else { - $tooltip = ''; - } - if ($disabled) { - $disabled = 'disabled="disabled"'; - } else { - $disabled = ''; - } - if ($jsconfirmmessage){ - $jsconfirmmessage = addslashes_js($jsconfirmmessage); - $jsconfirmmessage = 'onclick="return confirm(\''. $jsconfirmmessage .'\');" '; - } - $output .= '
"; - - if ($return) { - return $output; - } else { - echo $output; - } -} - - -/** - * Print a spacer image with the option of including a line break. - * - * @global object - * @param int $height The height in pixels to make the spacer - * @param int $width The width in pixels to make the spacer - * @param boolean $br If set to true a BR is written after the spacer - */ -function print_spacer($height=1, $width=1, $br=true, $return=false) { - global $CFG; - $output = ''; - - $output .= ''; - if ($br) { - $output .= '
'."\n"; - } - - if ($return) { - return $output; - } else { - echo $output; - } -} - -/** - * Given the path to a picture file in a course, or a URL, - * this function includes the picture in the page. - * - * @global object - * @param string $path The path the to the picture - * @param int $courseid The courseid the picture is associated with if any - * @param int $height The height of the picture in pixels if known - * @param int $width The width of the picture in pixels if known - * @param string $link If set the image is wrapped with this link - * @param bool $return If true the HTML is returned rather than being echo'd - * @return string|void Depending on $return - */ -function print_file_picture($path, $courseid=0, $height='', $width='', $link='', $return=false) { - global $CFG; - $output = ''; - - if ($height) { - $height = 'height="'. $height .'"'; - } - if ($width) { - $width = 'width="'. $width .'"'; - } - if ($link) { - $output .= ''; - } - if (substr(strtolower($path), 0, 7) == 'http://') { - $output .= ''; - - } else if ($courseid) { - $output .= 'picture is used. - * @param int $size Size in pixels. Special values are (true/1 = 100px) and (false/0 = 35px) for backward compatability - * @param boolean $return If false print picture to current page, otherwise return the output as string - * @param boolean $link enclose printed image in a link the user's profile (default true). - * @param string $target link target attribute. Makes the profile open in a popup window. - * @param boolean $alttext add non-blank alt-text to the image. (Default true, set to false for purely - * decorative images, or where the username will be printed anyway.) - * @return string|void String or nothing, depending on $return. - */ -function print_user_picture($user, $courseid, $picture=NULL, $size=0, $return=false, $link=true, $target='', $alttext=true) { - global $CFG, $DB, $OUTPUT; - - $needrec = false; - // only touch the DB if we are missing data... - if (is_object($user)) { - // Note - both picture and imagealt _can_ be empty - // what we are trying to see here is if they have been fetched - // from the DB. We should use isset() _except_ that some installs - // have those fields as nullable, and isset() will return false - // on null. The only safe thing is to ask array_key_exists() - // which works on objects. property_exists() isn't quite - // what we want here... - if (! (array_key_exists('picture', $user) - && ($alttext && array_key_exists('imagealt', $user) - || (isset($user->firstname) && isset($user->lastname)))) ) { - $needrec = true; - $user = $user->id; - } - } else { - if ($alttext) { - // we need firstname, lastname, imagealt, can't escape... - $needrec = true; - } else { - $userobj = new StdClass; // fake it to save DB traffic - $userobj->id = $user; - $userobj->picture = $picture; - $user = clone($userobj); - unset($userobj); - } - } - if ($needrec) { - $user = $DB->get_record('user', array('id'=>$user), 'id,firstname,lastname,imagealt'); - } - - if ($link) { - $url = '/user/view.php?id='. $user->id .'&course='. $courseid ; - if ($target) { - $target='onclick="return openpopup(\''.$url.'\');"'; - } - $output = ''; - } else { - $output = ''; - } - if (empty($size)) { - $file = 'f2'; - $size = 35; - } else if ($size === true or $size == 1) { - $file = 'f1'; - $size = 100; - } else if ($size >= 50) { - $file = 'f1'; - } else { - $file = 'f2'; - } - $class = "userpicture"; - - if (is_null($picture)) { - $picture = $user->picture; - } - - if ($picture) { // Print custom user picture - require_once($CFG->libdir.'/filelib.php'); - $src = get_file_url($user->id.'/'.$file.'.jpg', null, 'user'); - } else { // Print default user pictures (use theme version if available) - $class .= " defaultuserpic"; - $src = $OUTPUT->old_icon_url('u/' . $file); - } - $imagealt = ''; - if ($alttext) { - if (!empty($user->imagealt)) { - $imagealt = $user->imagealt; - } else { - $imagealt = get_string('pictureof','',fullname($user)); - } - } - - $output .= "\"".s($imagealt).'"'; - if ($link) { - $output .= ''; - } - - if ($return) { - return $output; - } else { - echo $output; - } -} - /** * Prints a summary of a user in a nice little box. * @@ -3599,43 +3249,6 @@ function print_group_picture($group, $courseid, $large=false, $return=false, $li } } -/** - * Print a png image. - * - * @global object - * @staticvar bool $recentIE - * @param string $url The URL of the image to display - * @param int $sizex The width of the image in pixels - * @param int $sizey The height of the image in pixels - * @param boolean $return If true the HTML is returned rather than echo'd - * @param string $parameters Additional HTML attributes to set - * @return string|bool Depending on $return - */ -function print_png($url, $sizex, $sizey, $return, $parameters='alt=""') { - global $OUTPUT; - static $recentIE; - - if (!isset($recentIE)) { - $recentIE = check_browser_version('MSIE', '5.0'); - } - - if ($recentIE) { // work around the HORRIBLE bug IE has with alpha transparencies - $output .= ''; - } else { - $output .= ''."\n"; - if ($usehtmleditor) { - $str .= htmlspecialchars($value); // needed for editing of cleaned text! - } else { - $str .= s($value); - } - $str .= ''."\n"; - - if ($return) { - return $str; - } - echo $str; -} - /** * Returns a turn edit on/off button for course in a self contained form. * Used to be an icon, but it's now a simple form button @@ -4313,6 +3863,7 @@ function print_timer_selector($timelimit = 0, $unit = '', $name = 'timelimit', $ * Showing all possible numerical grades and scales * * @todo Finish documenting this function + * @todo Deprecate: this is only used in a few contrib modules * * @global object * @param int $courseid The course ID @@ -4353,35 +3904,6 @@ function print_grade_menu($courseid, $name, $current, $includenograde=true, $ret } } -/** - * Prints a scale menu (as part of an existing form) including help button - * Just like {@link print_grade_menu()} but without the numeric grades - * - * @global object - * @param int $courseid ? - * @param string $name ? - * @param string $current ? - * @param boolean $return If set to true returns rather than echo's - * @return string|bool Depending on value of $return - */ -function print_scale_menu($courseid, $name, $current, $return=false) { - - global $CFG, $OUTPUT; - - $output = ''; - $strscales = get_string('scales'); - $output .= choose_from_menu(get_scales_menu($courseid), $name, $current, '', '', 0, true); - - $linkobject = ''.$strscales.''; - $output .= link_to_popup_window ('/course/scales.php?id='. $courseid .'&list=true', 'ratingscales', - $linkobject, 400, 500, $strscales, 'none', true); - if ($return) { - return $output; - } else { - echo $output; - } -} - /** * Prints a help button about a scale * @@ -4490,95 +4012,6 @@ function editorhelpbutton(){ return link_to_popup_window(s('/lib/form/editorhelp.php?'.$paramstring), 'popup', $linkobject, 400, 500, $alttag, 'none', true); } -/** - * Print a help button. - * - * @global object - * @global object - * @uses DEBUG_DEVELOPER - * @param string $page The keyword that defines a help page - * @param string $title The title of links, rollover tips, alt tags etc - * 'Help with' (or the language equivalent) will be prefixed and '...' will be stripped. - * @param string $module Which module is the page defined in - * @param mixed $image Use a help image for the link? (true/false/"both") - * @param boolean $linktext If true, display the title next to the help icon. - * @param string $text If defined then this text is used in the page, and - * the $page variable is ignored. - * @param boolean $return If true then the output is returned as a string, if false it is printed to the current page. - * @param string $imagetext The full text for the helpbutton icon. If empty use default help.gif - * @return string|void Depending on value of $return - */ -function helpbutton($page, $title, $module='moodle', $image=true, $linktext=false, $text='', $return=false, - $imagetext='') { - global $CFG, $COURSE, $OUTPUT; - - //warning if ever $text parameter is used - //$text option won't work properly because the text needs to be always cleaned and, - // when cleaned... html tags always break, so it's unusable. - if ( isset($text) && $text!='') { - debugging('Warning: it\'s not recommended to use $text parameter in helpbutton ($page=' . $page . ', $module=' . $module . ') function', DEBUG_DEVELOPER); - } - - // Catch references to the old text.html and emoticons.html help files that - // were renamed in MDL-13233. - if (in_array($page, array('text', 'emoticons', 'richtext'))) { - $oldname = $page; - $page .= '2'; - debugging("You are referring to the old help file '$oldname'. " . - "This was renamed to '$page' becuase of MDL-13233. " . - "Please update your code.", DEBUG_DEVELOPER); - } - - if ($module == '') { - $module = 'moodle'; - } - - if ($title == '' && $linktext == '') { - debugging('Error in call to helpbutton function: at least one of $title and $linktext is required'); - } - - // Warn users about new window for Accessibility - $tooltip = get_string('helpprefix2', '', trim($title, ". \t")) .' ('.get_string('newwindow').')'; - - $linkobject = ''; - - if ($image) { - if ($linktext) { - // MDL-7469 If text link is displayed with help icon, change to alt to "help with this". - $linkobject .= $title.' '; - $tooltip = get_string('helpwiththis'); - } - if ($imagetext) { - $linkobject .= $imagetext; - } else { - $linkobject .= ''.s(strip_tags($tooltip)).''; - } - } else { - $linkobject .= $tooltip; - } - - // fix for MDL-7734 - if ($text) { - $url = '/help.php?text='. s(urlencode($text)); - } else { - $url = '/help.php?module='. $module .'&file='. $page .'.html'; - // fix for MDL-7734 - if (!empty($COURSE->lang)) { - $url .= '&forcelang=' . $COURSE->lang; - } - } - - $link = '' . link_to_popup_window($url, 'popup', - $linkobject, 400, 500, $tooltip, 'none', true) . ''; - - if ($return) { - return $link; - } else { - echo $link; - } -} - /** * Print a help button. * @@ -4664,36 +4097,6 @@ function notice ($message, $link='', $course=NULL) { exit(1); // general error code } -/** - * Print a message along with "Yes" and "No" links for the user to continue. - * - * @global object - * @param string $message The text to display - * @param string $linkyes The link to take the user to if they choose "Yes" - * @param string $linkno The link to take the user to if they choose "No" - * @param string $optionyes The yes option to show on the notice - * @param string $optionsno The no option to show - * @param string $methodyes Form action method to use if yes [post, get] - * @param string $methodno Form action method to use if no [post, get] - * @return void Output is echo'd - */ -function notice_yesno ($message, $linkyes, $linkno, $optionsyes=NULL, $optionsno=NULL, $methodyes='post', $methodno='post') { - - global $CFG; - - $message = clean_text($message); - $linkyes = clean_text($linkyes); - $linkno = clean_text($linkno); - - print_box_start('generalbox', 'notice'); - echo '

'. $message .'

'; - echo '
'; - print_single_button($linkyes, $optionsyes, get_string('yes'), $methodyes, $CFG->framename); - print_single_button($linkno, $optionsno, get_string('no'), $methodno, $CFG->framename); - echo '
'; - print_box_end(); -} - /** * Redirects the user to another page, after printing a notice * @@ -4856,93 +4259,6 @@ function obfuscate_mailto($email, $label='', $dimmed=false) { obfuscate_text($label)); } -/** - * Prints a single paging bar to provide access to other pages (usually in a search) - * - * @param int $totalcount Thetotal number of entries available to be paged through - * @param int $page The page you are currently viewing - * @param int $perpage The number of entries that should be shown per page - * @param mixed $baseurl If this is a string then it is the url which will be appended with $pagevar, an equals sign and the page number. - * If this is a moodle_url object then the pagevar param will be replaced by the page no, for each page. - * @param string $pagevar This is the variable name that you use for the page number in your code (ie. 'tablepage', 'blogpage', etc) - * @param bool $nocurr do not display the current page as a link - * @param bool $return whether to return an output string or echo now - * @return bool|string depending on $result - */ -function print_paging_bar($totalcount, $page, $perpage, $baseurl, $pagevar='page',$nocurr=false, $return=false) { - $maxdisplay = 18; - $output = ''; - - if ($totalcount > $perpage) { - $output .= '
'; - $output .= get_string('page') .':'; - if ($page > 0) { - $pagenum = $page - 1; - if (!is_a($baseurl, 'moodle_url')){ - $output .= ' () '; - } else { - $output .= ' () '; - } - } - if ($perpage > 0) { - $lastpage = ceil($totalcount / $perpage); - } else { - $lastpage = 1; - } - if ($page > 15) { - $startpage = $page - 10; - if (!is_a($baseurl, 'moodle_url')){ - $output .= ' 1 ...'; - } else { - $output .= ' 1 ...'; - } - } else { - $startpage = 0; - } - $currpage = $startpage; - $displaycount = $displaypage = 0; - while ($displaycount < $maxdisplay and $currpage < $lastpage) { - $displaypage = $currpage+1; - if ($page == $currpage && empty($nocurr)) { - $output .= '  '. $displaypage; - } else { - if (!is_a($baseurl, 'moodle_url')){ - $output .= '  '. $displaypage .''; - } else { - $output .= '  '. $displaypage .''; - } - - } - $displaycount++; - $currpage++; - } - if ($currpage < $lastpage) { - $lastpageactual = $lastpage - 1; - if (!is_a($baseurl, 'moodle_url')){ - $output .= ' ...'. $lastpage .' '; - } else { - $output .= ' ...'. $lastpage .' '; - } - } - $pagenum = $page + 1; - if ($pagenum != $displaypage) { - if (!is_a($baseurl, 'moodle_url')){ - $output .= '  ()'; - } else { - $output .= '  ()'; - } - } - $output .= '
'; - } - - if ($return) { - return $output; - } - - echo $output; - return true; -} - /** * This function is used to rebuild the tag because some formats (PLAIN and WIKI) * will transform it to html entities @@ -5186,42 +4502,6 @@ function get_docs_url($path) { return $CFG->docroot . '/' . str_replace('_utf8', '', current_language()) . '/' . $path; } -/** - * Returns a string containing a link to the user documentation. - * Also contains an icon by default. Shown to teachers and admin only. - * - * @global object - * @param string $path The page link after doc root and language, no leading slash. - * @param string $text The text to be displayed for the link - * @param string $iconpath The path to the icon to be displayed - * @return string Either the link or an empty string - */ -function doc_link($path='', $text='', $iconpath='') { - global $CFG; - - if (empty($CFG->docroot)) { - return ''; - } - - $url = get_docs_url($path); - - $target = ''; - if (!empty($CFG->doctonewwindow)) { - $target = " onclick=\"window.open('$url'); return false;\""; - } - - $str = ""; - - if (empty($iconpath)) { - $iconpath = $CFG->httpswwwroot . '/pix/docs.gif'; - } - - // alt left blank intentionally to prevent repetition in screenreaders - $str .= '' .$text. ''; - - return $str; -} - /** * Standard Debugging Function @@ -5325,58 +4605,6 @@ function print_location_comment($file, $line, $return = false) } -/** - * Returns an image of an up or down arrow, used for column sorting. To avoid unnecessary DB accesses, please - * provide this function with the language strings for sortasc and sortdesc. - * - * If no sort string is associated with the direction, an arrow with no alt text will be printed/returned. - * - * @global object - * @param string $direction 'up' or 'down' - * @param string $strsort The language string used for the alt attribute of this image - * @param bool $return Whether to print directly or return the html string - * @return string|void depending on $return - * - */ -function print_arrow($direction='up', $strsort=null, $return=false) { - global $OUTPUT; - - if (!in_array($direction, array('up', 'down', 'right', 'left', 'move'))) { - return null; - } - - $return = null; - - switch ($direction) { - case 'up': - $sortdir = 'asc'; - break; - case 'down': - $sortdir = 'desc'; - break; - case 'move': - $sortdir = 'asc'; - break; - default: - $sortdir = null; - break; - } - - // Prepare language string - $strsort = ''; - if (empty($strsort) && !empty($sortdir)) { - $strsort = get_string('sort' . $sortdir, 'grades'); - } - - $return = ' '.$strsort.' '; - - if ($return) { - return $return; - } else { - echo $return; - } -} - /** * @return boolean true if the current language is right-to-left (Hebrew, Arabic etc) */ diff --git a/theme/standard/styles_ie6.css b/theme/standard/styles_ie6.css index 1c827d69b0..500adc1ebd 100755 --- a/theme/standard/styles_ie6.css +++ b/theme/standard/styles_ie6.css @@ -93,4 +93,7 @@ form.mform textarea { } #mod-quiz-edit .reorder .questioncontentcontainer .randomquestioncategory label{ width: 35%; -} \ No newline at end of file +} +#help_icon_tooltip .yui-tt-shadow-visible { + background-color: transparent; +} diff --git a/theme/standard/styles_layout.css b/theme/standard/styles_layout.css index 6996010a9a..efd4c00b80 100644 --- a/theme/standard/styles_layout.css +++ b/theme/standard/styles_layout.css @@ -595,6 +595,22 @@ div.hide { margin:0.2em 0pt; text-align:left; } +#help_icon_tooltip { + font-size: 0.7em; +} +#help_icon_tooltip h1 { + font-size: 1.1em; + font-weight: bold; +} +#help_icon_tooltip div.bd { + width: 35em; +} + +#help_icon_tooltip .readmore { + display: block; + font-style: italic; + margin-top:10px; +} /*** *** Forms -- 2.39.5