javascript MDL-23850 Moved mforms specific JavaScript to a separate file

This commit is contained in:
Sam Hemelryk
2010-08-19 05:43:06 +00:00
parent 0609036239
commit c7e3e61c70
6 changed files with 375 additions and 328 deletions
+288
View File
@@ -0,0 +1,288 @@
/**
* 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();
}
+1 -1
View File
@@ -100,7 +100,7 @@ YUI.add('moodle-form-dateselector', function(Y) {
} 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;
}
+42 -53
View File
@@ -1075,7 +1075,7 @@ EOS;
global $PAGE;
if (is_string($element)) {
$element = $this->_form->getElement($element);
}
}
if (is_object($element)) {
$element->_generateId();
$elementid = $element->getAttribute('id');
@@ -1091,6 +1091,23 @@ EOS;
}
}
}
/**
* 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')
)
);
}
}
/**
@@ -1803,22 +1820,14 @@ function validate_' . $this->_formName . '(frm) {
}
}
/**
* @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);
@@ -1830,17 +1839,13 @@ function validate_' . $this->_formName . '(frm) {
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);
}
/**
@@ -2238,16 +2243,20 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
}
/**
* @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());
}
}
}
/**
@@ -2256,17 +2265,10 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
* @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();
@@ -2282,30 +2284,17 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
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);
}
+10 -272
View File
@@ -675,223 +675,6 @@ function checknone() {
}
}
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
@@ -994,59 +777,6 @@ function findChildNodes(start, tagName, elementClass, elementID, elementName) {
}
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);
@@ -1224,7 +954,11 @@ function getElementsByClassName(oElm, strTagName, name) {
function openpopup(event, args) {
if (event) {
YAHOO.util.Event.preventDefault(event);
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
}
var fullurl = args.url;
@@ -1277,7 +1011,11 @@ emoticons_help = {
/** 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();
}
+33
View File
@@ -24,3 +24,36 @@ function lockoptions_timetoitems() {
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;
}
}
+1 -2
View File
@@ -105,8 +105,7 @@ form.popupform div {display: inline;}
/*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,