--- /dev/null
+/**
+ * This file contains JS functionality required by mforms and is included automatically
+ * when required.
+ */
+
+// Namespace for the form bits and bobs
+M.form = M.form || {};
+
+/**
+ * Initialises the show advanced functionality and events.
+ * This should only ever happen ONCE per page.
+ *
+ * @param {YUI} Y
+ * @param {object} config
+ */
+M.form.initShowAdvanced = function(Y, config) {
+ if (M.form.showAdvanced) {
+ return M.form.showAdvanced;
+ }
+ var showAdvanced = function(config) {
+ showAdvanced.superclass.constructor.apply(this, arguments);
+ }
+ showAdvanced.prototype = {
+ _advButtons : [],
+ _advAreas : [],
+ _stateInput : null,
+ initializer : function() {
+ this._advAreas = Y.all('form .advanced');
+ this._advButtons = Y.all('.showadvancedbtn');
+ if (this._advButtons.size() > 0) {
+ this._advButtons.item(0).get('form').get('elements').each(function(n){
+ if (this._stateInput == null && n.getAttribute('name') == 'mform_showadvanced_last') {
+ this._stateInput = n;
+ }
+ }, this);
+ this._advButtons.on('click', this.switchState, this);
+ }
+ },
+ /**
+ * Toggles between showing advanced items and hiding them.
+ * Should be fired by an event.
+ */
+ switchState : function(e) {
+ e.preventDefault();
+ if (this._stateInput.get('value')=='1') {
+ this._stateInput.set('value', '0');
+ this._advButtons.setAttribute('value', M.str.form.showadvanced);
+ this._advAreas.addClass('hide');
+ } else {
+ this._stateInput.set('value', '1');
+ this._advButtons.setAttribute('value', M.str.form.hideadvanced);
+ this._advAreas.removeClass('hide');
+ }
+ }
+ }
+ // Extend it with the YUI widget fw.
+ Y.extend(showAdvanced, Y.Base, showAdvanced.prototype, {
+ NAME : 'mform-showAdvanced'
+ })
+ M.form.showAdvanced = new showAdvanced(config);
+ return M.form.showAdvanced;
+}
+
+/**
+ * Initialises a manager for a forms dependencies.
+ * This should happen once per form.
+ */
+M.form.initFormDependencies = function(Y, formid, dependencies) {
+
+ // If the dependencies isn't an array or object we don't want to
+ // know about it
+ if (!Y.Lang.isArray(dependencies) && !Y.Lang.isObject(dependencies)) {
+ return false;
+ }
+
+ /**
+ * Fixes an issue with YUI's processing method of form.elements property
+ * in Internet Explorer.
+ * http://yuilibrary.com/projects/yui3/ticket/2528030
+ */
+ Y.Node.ATTRS.elements = {
+ getter: function() {
+ return Y.all(new Y.Array(this._node.elements, 0, true));
+ }
+ };
+
+ // Define the dependency manager if it hasn't already been defined.
+ M.form.dependencyManager = M.form.dependencyManager || (function(){
+ var dependencyManager = function(config) {
+ dependencyManager.superclass.constructor.apply(this, arguments);
+ }
+ dependencyManager.prototype = {
+ _form : null,
+ _depElements : [],
+ _nameCollections : [],
+ initializer : function(config) {
+ var i = 0, nodeName;
+ this._form = Y.one('#'+formid);
+ for (i in dependencies) {
+ this._depElements[i] = this.elementsByName(i);
+ if (this._depElements[i].size() == 0) {
+ continue;
+ }
+ this._depElements[i].each(function(node){
+ nodeName = node.get('nodeName').toUpperCase();
+ if (nodeName == 'INPUT') {
+ if (node.getAttribute('type').match(/^(button|submit|radio|checkbox)$/)) {
+ node.on('click', this.checkDependencies, this);
+ } else {
+ node.on('blur', this.checkDependencies, this);
+ }
+ node.on('change', this.checkDependencies, this);
+ } else if (nodeName == 'SELECT') {
+ node.on('change', this.checkDependencies, this);
+ } else {
+ node.on('click', this.checkDependencies, this);
+ node.on('blur', this.checkDependencies, this);
+ node.on('change', this.checkDependencies, this);
+ }
+ }, this);
+ }
+ this._form.all('reset').each(function(reset){
+ this._form.reset();
+ reset.on('click', this.checkDependencies, this);
+ }, this);
+
+ return this.checkDependencies(null);
+ },
+ /**
+ * Gets all elements in the form by thier name and returns
+ * a YUI NodeList
+ * @return Y.NodeList
+ */
+ elementsByName : function(name) {
+ if (!this._nameCollections[name]) {
+ var elements = [];
+ this._form.get('elements').each(function(){
+ if (this.getAttribute('name') == name) {
+ elements.push(this);
+ }
+ })
+ this._nameCollections[name] = new Y.NodeList(elements);
+ }
+ return this._nameCollections[name];
+ },
+ /**
+ * Checks the dependencies the form has an makes any changes to the
+ * form that are required.
+ *
+ * Changes are made by functions title _dependency_{dependencytype}
+ * and more can easily be introduced by defining further functions.
+ */
+ checkDependencies : function(e) {
+ var tolock = [],
+ tohide = [],
+ dependon, condition, value,
+ lock, hide, checkfunction, result;
+ for (dependon in dependencies) {
+ if (this._depElements[dependon].size() == 0) {
+ continue;
+ }
+ for (condition in dependencies[dependon]) {
+ for (value in dependencies[dependon][condition]) {
+ lock = false;
+ hide = false;
+ checkfunction = '_dependency_'+condition;
+ if (Y.Lang.isFunction(this[checkfunction])) {
+ result = this[checkfunction].apply(this, [this._depElements[dependon], value]);
+ } else {
+ result = this._dependency_default(this._depElements[dependon], value);
+ }
+ lock = result.lock || false;
+ hide = result.hide || false;
+ for (var ei in dependencies[dependon][condition][value]) {
+ var eltolock = dependencies[dependon][condition][value][ei];
+ if (hide) {
+ tohide[eltolock] = true;
+ }
+ if (tolock[eltolock] != null) {
+ tolock[eltolock] = lock || tolock[eltolock];
+ } else {
+ tolock[eltolock] = lock;
+ }
+ }
+ }
+ }
+ }
+ for (var el in tolock) {
+ this._disableElement(el, tolock[el]);
+ if (tohide.propertyIsEnumerable(el)) {
+ this._hideElement(el, tohide[el]);
+ }
+ }
+ return true;
+ },
+ /**
+ * Disabled all form elements with the given name
+ */
+ _disableElement : function(name, disabled) {
+ var els = this.elementsByName(name);
+ els.each(function(){
+ if (disabled) {
+ this.setAttribute('disabled', 'disabled');
+ } else {
+ this.removeAttribute('disabled');
+ }
+ })
+ },
+ /**
+ * Hides all elements with the given name.
+ */
+ _hideElement : function(name, hidden) {
+ var els = this.elementsByName(name);
+ els.each(function(){
+ var e = els.ancestor('.fitem');
+ if (e) {
+ e.setStyles({
+ display : (hidden)?'none':''
+ })
+ }
+ });
+ },
+ _dependency_notchecked : function(elements, value) {
+ var lock = false;
+ elements.each(function(){
+ lock = lock || !this.get('checked');
+ });
+ return {
+ lock : lock,
+ hide : false
+ }
+ },
+ _dependency_checked : function(elements, value) {
+ var lock = false;
+ elements.each(function(){
+ lock = lock || this.get('checked');
+ });
+ return {
+ lock : lock,
+ hide : false
+ }
+ },
+ _dependency_noitemselected : function(elements, value) {
+ var lock = false;
+ elements.each(function(){
+ lock = lock || this.get('selectedIndex') == -1;
+ });
+ return {
+ lock : lock,
+ hide : false
+ }
+ },
+ _dependency_eq : function(elements, value) {
+ var lock = false;
+ elements.each(function(){
+ lock = lock || this.get('value') == value;
+ });
+ return {
+ lock : lock,
+ hide : false
+ }
+ },
+ _dependency_hide : function(elements, value) {
+ return {
+ lock : false,
+ hide : true
+ }
+ },
+ _dependency_default : function(elements, value) {
+ var lock = false;
+ elements.each(function(){
+ lock = lock || this.get('value') != value;
+ });
+ return {
+ lock : lock,
+ hide : false
+ }
+ }
+ }
+ Y.extend(dependencyManager, Y.Base, dependencyManager.prototype, {
+ NAME : 'mform-dependency-manager'
+ });
+
+ return dependencyManager;
+ })();
+
+ return new M.form.dependencyManager();
+}
\ No newline at end of file
} else if (node.get('name').match(/\[day]/)) {
this.dayselect = node;
} else {
- node.on('focus', this.cancel_any_timeout, this);
+ node.on('focus', M.form.dateselector.cancel_any_timeout, M.form.dateselector);
node.on('blur', this.blur_event, this);
return;
}
global $PAGE;
if (is_string($element)) {
$element = $this->_form->getElement($element);
-}
+ }
if (is_object($element)) {
$element->_generateId();
$elementid = $element->getAttribute('id');
}
}
}
+
+ /**
+ * Returns a JS module definition for the mforms JS
+ * @return array
+ */
+ public static function get_js_module() {
+ global $CFG;
+ return array(
+ 'name' => 'mform',
+ 'fullpath' => '/lib/form/form.js',
+ 'requires' => array('base', 'node'),
+ 'strings' => array(
+ array('showadvanced', 'form'),
+ array('hideadvanced', 'form')
+ )
+ );
+ }
}
/**
}
}
- /**
- * @return string
- */
- function getLockOptionEndScript(){
-
- $iname = $this->getAttribute('id').'items';
- $js = '<script type="text/javascript">'."\n";
- $js .= '//<![CDATA['."\n";
- $js .= "var $iname = Array();\n";
-
+ function getLockOptionObject(){
+ $result = array();
foreach ($this->_dependencies as $dependentOn => $conditions){
- $js .= "{$iname}['$dependentOn'] = Array();\n";
+ $result[$dependentOn] = array();
foreach ($conditions as $condition=>$values) {
- $js .= "{$iname}['$dependentOn']['$condition'] = Array();\n";
+ $result[$dependentOn][$condition] = array();
foreach ($values as $value=>$dependents) {
- $js .= "{$iname}['$dependentOn']['$condition']['$value'] = Array();\n";
+ $result[$dependentOn][$condition][$value] = array();
$i = 0;
foreach ($dependents as $dependent) {
$elements = $this->_getElNamesRecursive($dependent);
if ($element == $dependentOn) {
continue;
}
- $js .= "{$iname}['$dependentOn']['$condition']['$value'][$i]='$element';\n";
- $i++;
+ $result[$dependentOn][$condition][$value][] = $element;
}
}
}
}
}
- $js .="lockoptionsallsetup('".$this->getAttribute('id')."');\n";
- $js .='//]]>'."\n";
- $js .='</script>'."\n";
- return $js;
+ return array($this->getAttribute('id'), $result);
}
/**
}
/**
+ * @global moodle_page $PAGE
* @param object $form Passed by reference
*/
function finishForm(&$form){
+ global $PAGE;
if ($form->isFrozen()){
$this->_hiddenHtml = '';
}
parent::finishForm($form);
- if ((!$form->isFrozen()) && ('' != ($script = $form->getLockOptionEndScript()))) {
- // add a lockoptions script
- $this->_html = $this->_html . "\n" . $script;
+ if (!$form->isFrozen()) {
+ $args = $form->getLockOptionObject();
+ if (count($args[1]) > 0) {
+ $PAGE->requires->js_init_call('M.form.initFormDependencies', $args, false, moodleform::get_js_module());
+ }
}
}
/**
* @param object $header An HTML_QuickForm_header element being visited
* @access public
* @return void
+ * @global moodle_page $PAGE
*/
function renderHeader(&$header) {
global $PAGE;
- static $advformcount;
-
- // This ensures that if 2(+) advanced buttons are used
- // that all show/hide buttons appear in the correct place
- // Because of now using $PAGE->requires->js_function_call
- if ($advformcount==null) {
- $advformcount = 1;
- }
$name = $header->getName();
if (isset($this->_advancedElements[$name])){
$header_html =str_replace('{advancedimg}', $this->_advancedHTML, $header_html);
+ $elementName='mform_showadvanced';
+ if ($this->_showAdvanced==0){
+ $buttonlabel = get_string('showadvanced', 'form');
+ } else {
+ $buttonlabel = get_string('hideadvanced', 'form');
+ }
+ $button = '<input name="'.$elementName.'" class="showadvancedbtn" value="'.$buttonlabel.'" type="submit" />';
+ $PAGE->requires->js_init_call('M.form.initShowAdvanced', array(), false, moodleform::get_js_module());
+ $header_html = str_replace('{button}', $button, $header_html);
} else {
$header_html =str_replace('{advancedimg}', '', $header_html);
- }
- $elementName='mform_showadvanced';
- if ($this->_showAdvanced==0){
- $buttonlabel = get_string('showadvanced', 'form');
- } else {
- $buttonlabel = get_string('hideadvanced', 'form');
- }
-
- if (isset($this->_advancedElements[$name])){
- $PAGE->requires->yui2_lib('event');
- // this is tricky - the first submit button on form is "clicked" if user presses enter
- // we do not want to "submit" using advanced button if javascript active
- $button_nojs = '<input name="'.$elementName.'" id="'.$elementName.(string)$advformcount.'" class="showadvancedbtn" value="'.$buttonlabel.'" type="submit" />';
-
- $buttonlabel = addslashes_js($buttonlabel);
- $PAGE->requires->string_for_js('showadvanced', 'form');
- $PAGE->requires->string_for_js('hideadvanced', 'form');
- $PAGE->requires->js_function_call('showAdvancedInit', Array($elementName.(string)$advformcount, $elementName, $buttonlabel));
-
- $advformcount++;
- $header_html = str_replace('{button}', $button_nojs, $header_html);
- } else {
$header_html = str_replace('{button}', '', $header_html);
}
}
}
-function lockoptions(formid, master, subitems) {
- // Subitems is an array of names of sub items.
- // Optionally, each item in subitems may have a
- // companion hidden item in the form with the
- // same name but prefixed by "h".
- var form = document.forms[formid];
-
- if (eval("form."+master+".checked")) {
- for (i=0; i<subitems.length; i++) {
- unlockoption(form, subitems[i]);
- }
- } else {
- for (i=0; i<subitems.length; i++) {
- lockoption(form, subitems[i]);
- }
- }
- return(true);
-}
-
-function lockoption(form,item) {
- eval("form."+item+".disabled=true");/* IE thing */
- if(form.elements['h'+item]) {
- eval("form.h"+item+".value=1");
- }
-}
-
-function unlockoption(form,item) {
- eval("form."+item+".disabled=false");/* IE thing */
- if(form.elements['h'+item]) {
- eval("form.h"+item+".value=0");
- }
-}
-
-/**
- * Get the value of the 'virtual form element' with a particular name. That is,
- * abstracts away the difference between a normal form element, like a select
- * which is a single HTML element with a .value property, and a set of radio
- * buttons, which is several HTML elements.
- *
- * @param form a HTML form.
- * @param master the name of an element in that form.
- * @return the value of that element.
- */
-function get_form_element_value(form, name) {
- var element = form[name];
- if (!element) {
- return null;
- }
- if (element.tagName) {
- // Ordinarly thing like a select box.
- return element.value;
- }
- // Array of things, like radio buttons.
- for (var j = 0; j < element.length; j++) {
- var el = element[j];
- if (el.checked) {
- return el.value;
- }
- }
- return null;
-}
-
-
-/**
- * Set the disabled state of the 'virtual form element' with a particular name.
- * This abstracts away the difference between a normal form element, like a select
- * which is a single HTML element with a .value property, and a set of radio
- * buttons, which is several HTML elements.
- *
- * @param form a HTML form.
- * @param master the name of an element in that form.
- * @param disabled the disabled state to set.
- */
-function set_form_element_disabled(form, name, disabled) {
- var element = form[name];
- if (!element) {
- return;
- }
- if (element.tagName) {
- // Ordinarly thing like a select box.
- element.disabled = disabled;
- }
- // Array of things, like radio buttons.
- for (var j = 0; j < element.length; j++) {
- var el = element[j];
- el.disabled = disabled;
- }
-}
-
-/**
- * Set the hidden state of the 'virtual form element' with a particular name.
- * This abstracts away the difference between a normal form element, like a select
- * which is a single HTML element with a .value property, and a set of radio
- * buttons, which is several HTML elements.
- *
- * @param form a HTML form.
- * @param master the name of an element in that form.
- * @param hidden the hidden state to set.
- */
-function set_form_element_hidden(form, name, hidden) {
- var element = form[name];
- if (!element) {
- return;
- }
- if (element.tagName) {
- var el = findParentNode(element, 'DIV', 'fitem', false);
- if (el!=null) {
- el.style.display = hidden ? 'none' : '';
- el.style.visibility = hidden ? 'hidden' : '';
- }
- }
- // Array of things, like radio buttons.
- for (var j = 0; j < element.length; j++) {
- var el = findParentNode(element[j], 'DIV', 'fitem', false);
- if (el!=null) {
- el.style.display = hidden ? 'none' : '';
- el.style.visibility = hidden ? 'hidden' : '';
- }
- }
-}
-
-function lockoptionsall(formid) {
- var form = document.forms[formid];
- var dependons = eval(formid + 'items');
- var tolock = [];
- var tohide = [];
- for (var dependon in dependons) {
- // change for MooTools compatibility
- if (!dependons.propertyIsEnumerable(dependon)) {
- continue;
- }
- if (!form[dependon]) {
- continue;
- }
- for (var condition in dependons[dependon]) {
- for (var value in dependons[dependon][condition]) {
- var lock;
- var hide = false;
- switch (condition) {
- case 'notchecked':
- lock = !form[dependon].checked;break;
- case 'checked':
- lock = form[dependon].checked;break;
- case 'noitemselected':
- lock = form[dependon].selectedIndex == -1;break;
- case 'eq':
- lock = get_form_element_value(form, dependon) == value;break;
- case 'hide':
- // hide as well as disable
- hide = true;break;
- default:
- lock = get_form_element_value(form, dependon) != value;break;
- }
- for (var ei in dependons[dependon][condition][value]) {
- var eltolock = dependons[dependon][condition][value][ei];
- if (hide) {
- tohide[eltolock] = true;
- }
- if (tolock[eltolock] != null) {
- tolock[eltolock] = lock || tolock[eltolock];
- } else {
- tolock[eltolock] = lock;
- }
- }
- }
- }
- }
- for (var el in tolock) {
- // change for MooTools compatibility
- if (!tolock.propertyIsEnumerable(el)) {
- continue;
- }
- set_form_element_disabled(form, el, tolock[el]);
- if (tohide.propertyIsEnumerable(el)) {
- set_form_element_hidden(form, el, tolock[el]);
- }
- }
- return true;
-}
-
-function lockoptionsallsetup(formid) {
- var form = document.forms[formid];
- var dependons = eval(formid+'items');
- for (var dependon in dependons) {
- // change for MooTools compatibility
- if (!dependons.propertyIsEnumerable(dependon)) {
- continue;
- }
- var masters = form[dependon];
- if (!masters) {
- continue;
- }
- if (masters.tagName) {
- // If master is radio buttons, we get an array, otherwise we don't.
- // Convert both cases to an array for convinience.
- masters = [masters];
- }
- for (var j = 0; j < masters.length; j++) {
- master = masters[j];
- master.formid = formid;
- master.onclick = function() {return lockoptionsall(this.formid);};
- master.onblur = function() {return lockoptionsall(this.formid);};
- master.onchange = function() {return lockoptionsall(this.formid);};
- }
- }
- for (var i = 0; i < form.elements.length; i++) {
- var formelement = form.elements[i];
- if (formelement.type=='reset') {
- formelement.formid = formid;
- formelement.onclick = function() {this.form.reset();return lockoptionsall(this.formid);};
- formelement.onblur = function() {this.form.reset();return lockoptionsall(this.formid);};
- formelement.onchange = function() {this.form.reset();return lockoptionsall(this.formid);};
- }
- }
- return lockoptionsall(formid);
-}
-
/**
* Either check, or uncheck, all checkboxes inside the element with id is
* @param id the id of the container
}
return children;
}
-/*
- elementSetHide (elements, hide)
-
- Adds or removes the "hide" class for the specified elements depending on boolean hide.
-*/
-function elementShowAdvanced(elements, show) {
- for (var elementIndex in elements) {
- element = elements[elementIndex];
- element.className = element.className.replace(new RegExp(' ?hide'), '')
- if(!show) {
- element.className += ' hide';
- }
- }
-}
-
-function showAdvancedInit(addBefore, nameAttr, buttonLabel, hideText, showText) {
- var showHideButton = document.createElement("input");
- showHideButton.type = 'button';
- showHideButton.value = buttonLabel;
- showHideButton.name = nameAttr;
- showHideButton.moodle = {
- hideLabel: M.str.form.hideadvanced,
- showLabel: M.str.form.showadvanced
- };
- YAHOO.util.Event.addListener(showHideButton, 'click', showAdvancedOnClick);
- el = document.getElementById(addBefore);
- el.parentNode.insertBefore(showHideButton, el);
-}
-
-function showAdvancedOnClick(e) {
- var button = e.target ? e.target : e.srcElement;
-
- var toSet=findChildNodes(button.form, null, 'advanced');
- var buttontext = '';
- if (button.form.elements['mform_showadvanced_last'].value == '0' || button.form.elements['mform_showadvanced_last'].value == '' ) {
- elementShowAdvanced(toSet, true);
- buttontext = button.moodle.hideLabel;
- button.form.elements['mform_showadvanced_last'].value = '1';
- } else {
- elementShowAdvanced(toSet, false);
- buttontext = button.moodle.showLabel;
- button.form.elements['mform_showadvanced_last'].value = '0';
- }
- var formelements = button.form.elements;
- // Fixed MDL-10506
- for (var i = 0; i < formelements.length; i++) {
- if (formelements[i] && formelements[i].name && (formelements[i].name=='mform_showadvanced')) {
- formelements[i].value = buttontext;
- }
- }
- //never submit the form if js is enabled.
- return false;
-}
function unmaskPassword(id) {
var pw = document.getElementById(id);
function openpopup(event, args) {
if (event) {
- YAHOO.util.Event.preventDefault(event);
+ if (event.preventDefault) {
+ event.preventDefault();
+ } else {
+ event.returnValue = false;
+ }
}
var fullurl = args.url;
/** Close the current browser window. */
function close_window(e) {
- YAHOO.util.Event.preventDefault(e);
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
self.close();
}
function lockoptions_timefromitems() {
lockoptions('searchform','timetorestrict', timetoitems);
}
+
+function lockoptions(formid, master, subitems) {
+ // Subitems is an array of names of sub items.
+ // Optionally, each item in subitems may have a
+ // companion hidden item in the form with the
+ // same name but prefixed by "h".
+ var form = document.forms[formid], i;
+ if (form[master].checked) {
+ for (i=0; i<subitems.length; i++) {
+ unlockoption(form, subitems[i]);
+ }
+ } else {
+ for (i=0; i<subitems.length; i++) {
+ lockoption(form, subitems[i]);
+ }
+ }
+ return(true);
+}
+
+
+function lockoption(form,item) {
+ form[item].setAttribute('disabled', 'disabled');
+ if (form.elements['h'+item]) {
+ form.elements['h'+item].value=1;
+ }
+}
+
+function unlockoption(form,item) {
+ form[item].removeAttribute('disabled');
+ if (form.elements['h'+item]) {
+ form.elements['h'+item].value=0;
+ }
+}
\ No newline at end of file
/*Accessibility: text 'seen' by screen readers but not visual users. */
.accesshide {position:absolute;top:-100000px;left:10px;font-weight:normal;font-size:1em;}
span.hide,
-div.hide,
-.jsenabled .advancedbutton .showadvancedbtn {display:none;}
+div.hide {display:none;}
.invisiblefieldset {display:inline;border-width:0;padding:0;margin:0;}
/*Accessibility: Skip block link, for keyboard-only users. */
a.skip-block,