MDL-30637 Refactor Advanced fileds functionality

The displaying of advanced items has been refactored. The changes are:

* The Advanced button is replaced by the Show Less/More link
* The Show less/more link controls advanced elements only within the section
  it is located at
* The Show less/more state of sections is preserved between form submissions
* When javascript is off, all advanced elements will be displayed by default,
  no show/hide controls will exists on the page
This commit is contained in:
Ruslan Kabalin 2013-01-24 14:28:40 +00:00
parent a4f1834dca
commit ac5e6ca4d1
5 changed files with 149 additions and 158 deletions

View File

@ -58,6 +58,8 @@ $string['security'] = 'Security';
$string['selectallornone'] = 'Select all/none';
$string['selected'] = 'Selected';
$string['showadvanced'] = 'Show advanced';
$string['showless'] = 'Show less...';
$string['showmore'] = 'Show more...';
$string['showeditortoolbar'] = 'Show editing tools';
$string['somefieldsrequired'] = 'There are required fields in this form marked {$a}.';
$string['time'] = 'Time';

View File

@ -6,58 +6,6 @@
// 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._stateInput = new Y.NodeList(document.getElementsByName('mform_showadvanced_last'));
this._advButtons.on('click', this.switchState, this);
this._advButtons.set('type', 'button');
}
},
/**
* 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;
};
/**
* Stores a list of the dependencyManager for each form on the page.
*/

View File

@ -0,0 +1,104 @@
YUI.add('moodle-form-showadvanced', function(Y) {
/**
* Provides the form showadvanced class
*
* @module moodle-form-showadvanced
*/
/**
* A class for a showadvanced
*
* @param {Object} config Object literal specifying showadvanced configuration properties.
* @class M.form.showadvanced
* @constructor
* @extends Y.Base
*/
function SHOWADVANCED(config) {
SHOWADVANCED.superclass.constructor.apply(this, [config]);
}
var SELECTORS = {
FIELDSETCONTAINSADVANCED : 'fieldset.containsadvancedelements',
DIVFITEMADVANCED : 'div.fitem.advanced',
DIVFCONTAINER : 'div.fcontainer'
},
CSS = {
HIDE : 'hide',
MORELESSTOGGLER : 'morelesstoggler'
},
ATTRS = {};
/**
* Static property provides a string to identify the JavaScript class.
*
* @property NAME
* @type String
* @static
*/
SHOWADVANCED.NAME = 'moodle-form-showadvanced';
/**
* Static property used to define the default attribute configuration for the Showadvanced.
*
* @property ATTRS
* @type String
* @static
*/
SHOWADVANCED.ATTRS = ATTRS;
/**
* The form ID attribute definition
*
* @attribute formid
* @type String
* @default ''
* @writeOnce
*/
ATTRS.formid = {
value : null
};
Y.extend(SHOWADVANCED, Y.Base, {
initializer : function() {
var fieldlist = Y.Node.all('#'+this.get('formid')+' '+SELECTORS.FIELDSETCONTAINSADVANCED);
// Look through fieldset divs that contain advanced elements
fieldlist.each(this.process_fieldset, this);
// Subscribe more/less links to click event
Y.one('#'+this.get('formid')).delegate('click', this.switch_state, SELECTORS.FIELDSETCONTAINSADVANCED+' .'+CSS.MORELESSTOGGLER);
},
process_fieldset : function(fieldset) {
var statuselement = new Y.one('input[name=mform_showmore_'+fieldset.get('id')+']');
var morelesslink = Y.Node.create('<a href="#"></a>');
morelesslink.addClass(CSS.MORELESSTOGGLER);
if (statuselement.get('value') === '0') {
morelesslink.setHTML(M.str.form.showmore);
// hide advanced stuff initially
fieldset.all(SELECTORS.DIVFITEMADVANCED).addClass(CSS.HIDE);
} else {
morelesslink.setHTML(M.str.form.showless);
}
fieldset.one(SELECTORS.DIVFCONTAINER).append(morelesslink);
},
switch_state : function(e) {
e.preventDefault();
var fieldset = this.ancestor(SELECTORS.FIELDSETCONTAINSADVANCED);
// toggle collapsed class
fieldset.all(SELECTORS.DIVFITEMADVANCED).toggleClass(CSS.HIDE);
// get corresponding hidden variable
var statuselement = new Y.one('input[name=mform_showmore_'+fieldset.get('id')+']');
// invert it and change the link text
if (statuselement.get('value') === '0') {
statuselement.set('value', 1);
this.setHTML(M.util.get_string('showless', 'form'));
} else {
statuselement.set('value', 0);
this.setHTML(M.util.get_string('showmore', 'form'));
}
}
});
M.form = M.form || {};
M.form.showadvanced = M.form.showadvanced || function(params) {
return new SHOWADVANCED(params);
};
}, '@VERSION@', {requires:['base', 'node', 'selector-css3']});

View File

@ -1225,11 +1225,7 @@ abstract class moodleform {
return array(
'name' => 'mform',
'fullpath' => '/lib/form/form.js',
'requires' => array('base', 'node'),
'strings' => array(
array('showadvanced', 'form'),
array('hideadvanced', 'form')
)
'requires' => array('base', 'node')
);
}
}
@ -1277,13 +1273,6 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
*/
var $_disableShortforms = false;
/**
* Whether to display advanced elements (on page load)
*
* @var boolean
*/
var $_showAdvanced = null;
/** @var bool whether to automatically initialise M.formchangechecker for this form. */
protected $_use_form_change_checker = true;
@ -1369,13 +1358,6 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
} elseif (isset($this->_advancedElements[$elementName])) {
unset($this->_advancedElements[$elementName]);
}
if ($advanced && $this->getElementType('mform_showadvanced_last')===false){
$this->setShowAdvanced();
$this->registerNoSubmitButton('mform_showadvanced');
$this->addElement('hidden', 'mform_showadvanced_last');
$this->setType('mform_showadvanced_last', PARAM_INT);
}
}
/**
@ -1401,6 +1383,29 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
$this->_collapsibleElements[$headerName] = !$expanded;
}
/**
* Use this method to add show more/less status element required for passing
* over the advanced elements visibility status on the form submission.
*
* @param string $headerName header element name
* @param boolean $showmore default false sets the advanced elements to be hidden.
*/
function addAdvancedStatusElement($headerName, $showmore=false){
// Add extra hidden element to store advanced items state for each section
if ($this->getElementType('mform_showmore_' . $headerName) === false) {
// see if we the form has been submitted already
$formshowmore = optional_param('mform_showmore_' . $headerName, -1, PARAM_INT);
if (!$showmore && $formshowmore != -1) {
// override showmore state with the form variable
$showmore = $formshowmore;
}
// create the form element for storing advanced items state
$this->addElement('hidden', 'mform_showmore_' . $headerName);
$this->setType('mform_showmore_' . $headerName, PARAM_INT);
$this->setConstant('mform_showmore_' . $headerName, (int)$showmore);
}
}
/**
* Use this method to indicate that the form will not be using shortforms.
*
@ -1410,53 +1415,6 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
$this->_disableShortforms = $disable;
}
/**
* Set whether to show advanced elements in the form on first displaying form. Default is not to
* display advanced elements in the form until 'Show Advanced' is pressed.
*
* You can get the last state of the form and possibly save it for this user by using
* value 'mform_showadvanced_last' in submitted data.
*
* @param bool $showadvancedNow if true will show adavance elements.
*/
function setShowAdvanced($showadvancedNow = null){
if ($showadvancedNow === null){
if ($this->_showAdvanced !== null){
return;
} else { //if setShowAdvanced is called without any preference
//make the default to not show advanced elements.
$showadvancedNow = get_user_preferences(
textlib::strtolower($this->_formName.'_showadvanced', 0));
}
}
//value of hidden element
$hiddenLast = optional_param('mform_showadvanced_last', -1, PARAM_INT);
//value of button
$buttonPressed = optional_param('mform_showadvanced', 0, PARAM_RAW);
//toggle if button pressed or else stay the same
if ($hiddenLast == -1) {
$next = $showadvancedNow;
} elseif ($buttonPressed) { //toggle on button press
$next = !$hiddenLast;
} else {
$next = $hiddenLast;
}
$this->_showAdvanced = $next;
if ($showadvancedNow != $next){
set_user_preference($this->_formName.'_showadvanced', $next);
}
$this->setConstants(array('mform_showadvanced_last'=>$next));
}
/**
* Gets show advance value, if advance elements are visible it will return true else false
*
* @return bool
*/
function getShowAdvanced(){
return $this->_showAdvanced;
}
/**
* Call this method if you don't want the formchangechecker JavaScript to be
* automatically initialised for this form.
@ -1496,6 +1454,7 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
$lastHeader = null;
$lastHeaderAdvanced = false;
$anyAdvanced = false;
$anyError = false;
foreach (array_keys($this->_elements) as $elementIndex){
$element =& $this->_elements[$elementIndex];
@ -1503,6 +1462,7 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
if ($element->getType()=='header' || in_array($element->getName(), $stopFields)){
if ($anyAdvanced && !is_null($lastHeader)){
$this->setAdvanced($lastHeader->getName());
$this->addAdvancedStatusElement($lastHeader->getName(), $anyError);
}
$lastHeaderAdvanced = false;
unset($lastHeader);
@ -1514,14 +1474,19 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
if ($element->getType()=='header'){
$lastHeader =& $element;
$anyAdvanced = false;
$anyError = false;
$lastHeaderAdvanced = isset($this->_advancedElements[$element->getName()]);
} elseif (isset($this->_advancedElements[$element->getName()])){
$anyAdvanced = true;
if (isset($this->_errors[$element->getName()])) {
$anyError = true;
}
}
}
// the last header may not be closed yet...
if ($anyAdvanced && !is_null($lastHeader)){
$this->setAdvanced($lastHeader->getName());
$this->addAdvancedStatusElement($lastHeader->getName(), $anyError);
}
$renderer->setAdvancedElements($this->_advancedElements);
}
@ -2338,7 +2303,7 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
/** @var string Header Template string */
var $_headerTemplate =
"\n\t\t<legend class=\"ftoggler\">{header}</legend>\n\t\t<div class=\"advancedbutton\">{advancedimg}{button}</div><div class=\"fcontainer clearfix\">\n\t\t";
"\n\t\t<legend class=\"ftoggler\">{header}</legend>\n\t\t<div class=\"fcontainer clearfix\">\n\t\t";
/** @var string Template used when opening a fieldset */
var $_openFieldsetTemplate = "\n\t<fieldset class=\"{classes}\" {id}>";
@ -2363,13 +2328,6 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
*/
var $_collapsibleElements = array();
/**
* Whether to display advanced elements (on page load)
*
* @var integer 1 means show 0 means hide
*/
var $_showAdvanced;
/**
* Constructor
*/
@ -2419,7 +2377,6 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
$this->_reqHTML = $form->getReqHTML();
$this->_elementTemplates = str_replace('{req}', $this->_reqHTML, $this->_elementTemplates);
$this->_advancedHTML = $form->getAdvancedHTML();
$this->_showAdvanced = $form->getShowAdvanced();
$formid = $form->getAttribute('id');
parent::startForm($form);
if ($form->isFrozen()){
@ -2441,6 +2398,10 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
if (count($this->_collapsibleElements)) {
$PAGE->requires->yui_module('moodle-form-shortforms', 'M.form.shortforms', array(array('formid' => $formid)));
}
if (count($this->_advancedElements)){
$PAGE->requires->strings_for_js(array('showmore', 'showless'), 'form');
$PAGE->requires->yui_module('moodle-form-showadvanced', 'M.form.showadvanced', array(array('formid' => $formid)));
}
}
/**
@ -2460,13 +2421,9 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
$html = $this->_elementTemplates['default'];
}
if ($this->_showAdvanced){
$advclass = ' advanced';
} else {
$advclass = ' advanced hide';
}
if (isset($this->_advancedElements[$group->getName()])){
$html =str_replace(' {advanced}', $advclass, $html);
$html =str_replace(' {advanced}', ' advanced', $html);
$html =str_replace('{advancedimg}', $this->_advancedHTML, $html);
} else {
$html =str_replace(' {advanced}', '', $html);
@ -2515,13 +2472,8 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
}else{
$html = $this->_elementTemplates['default'];
}
if ($this->_showAdvanced){
$advclass = ' advanced';
} else {
$advclass = ' advanced hide';
}
if (isset($this->_advancedElements[$element->getName()])){
$html =str_replace(' {advanced}', $advclass, $html);
$html =str_replace(' {advanced}', ' advanced', $html);
} else {
$html =str_replace(' {advanced}', '', $html);
}
@ -2590,22 +2542,6 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
$header_html = str_replace('{header}', $header->toHtml(), $this->_headerTemplate);
}
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);
$header_html = str_replace('{button}', '', $header_html);
}
if ($this->_fieldsetsOpen > 0) {
$this->_html .= $this->_closeFieldsetTemplate;
$this->_fieldsetsOpen--;
@ -2620,6 +2556,10 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
}
}
if (isset($this->_advancedElements[$name])){
$fieldsetclasses[] = 'containsadvancedelements';
}
$openFieldsetTemplate = str_replace('{id}', $id, $this->_openFieldsetTemplate);
$openFieldsetTemplate = str_replace('{classes}', join(' ', $fieldsetclasses), $openFieldsetTemplate);

View File

@ -25,9 +25,6 @@ class user_add_filter_form extends moodleform {
// Add button
$mform->addElement('submit', 'addfilter', get_string('addfilter','filters'));
// Don't use last advanced state
$mform->setShowAdvanced(false);
}
}