MDL-55417 forms: Render form elements with a template

This change allows form elements to be overridden with a mustache template.
The template can even listen for form validation errors and supply the JS to
change the look of the form element when there is/isn't a validation error.

Initial support is for all core form elements including:

text, select, selectyesno and checkboxes, groups, dateselector, datetimeselector,
autocomplete, modvisible, advcheckbox, button, duration, filemanager, filepicker, editor, static, grading,
warning, textarea, password, url, submit, questioncategory, recaptcha.

Part of MDL-55071
This commit is contained in:
Damyon Wiese 2016-08-04 22:29:32 +08:00 committed by Dan Poltawski
parent ef18a21f93
commit 91bda4cd45
69 changed files with 1566 additions and 367 deletions

View File

@ -49,8 +49,12 @@ class edit_outcome_form extends moodleform {
$options = array();
$mform->addElement('selectwithlink', 'scaleid', get_string('scale'), $options, null,
array('link' => $CFG->wwwroot.'/grade/edit/scale/edit.php?courseid='.$COURSE->id, 'label' => get_string('scalescustomcreate')));
$mform->addElement('select', 'scaleid', get_string('scale'), $options);
$url = new moodle_url('/grade/edit/scale/edit.php', array('courseid' => $COURSE->id));
$label = get_string('scalescustomcreate');
$mform->addElement('static', 'scaleidlink', '', html_writer::link($url, $label));
$mform->addHelpButton('scaleid', 'typescale', 'grades');
$mform->addRule('scaleid', get_string('required'), 'required');

View File

@ -56,8 +56,11 @@ class edit_outcomeitem_form extends moodleform {
$options[$outcome->id] = $outcome->get_name();
}
}
$mform->addElement('selectwithlink', 'outcomeid', get_string('outcome', 'grades'), $options, null,
array('link' => $CFG->wwwroot.'/grade/edit/outcome/course.php?id='.$COURSE->id, 'label' => get_string('outcomeassigntocourse', 'grades')));
$url = new moodle_url('/grade/edit/outcome/course.php', array('id' => $COURSE->id));
$label = get_string('outcomeassigntocourse', 'grades');
$mform->addElement('select', 'outcomeid', get_string('outcome', 'grades'), $options);
$mform->addElement('static', 'outcomeidlink', '', html_writer::link($url, $label));
$mform->addHelpButton('outcomeid', 'outcome', 'grades');
$mform->addRule('outcomeid', get_string('required'), 'required');

View File

@ -1 +1 @@
define(["jquery","core/yui"],function(a,b){return{notifyFilterContentUpdated:function(c){c=a(c),b.use("event","moodle-core-event",function(b){a(document).trigger(M.core.event.FILTER_CONTENT_UPDATED,c);var d=new b.NodeList(c.get());b.fire(M.core.event.FILTER_CONTENT_UPDATED,{nodes:d})})},notifyEditorContentRestored:function(){b.use("event","moodle-core-event",function(b){a(document).trigger(M.core.event.EDITOR_CONTENT_RESTORED),b.fire(M.core.event.EDITOR_CONTENT_RESTORED)})}}});
define(["jquery","core/yui"],function(a,b){return{Events:{FORM_FIELD_VALIDATION:"core_form-field-validation"},notifyFilterContentUpdated:function(c){c=a(c),b.use("event","moodle-core-event",function(b){a(document).trigger(M.core.event.FILTER_CONTENT_UPDATED,c);var d=new b.NodeList(c.get());b.fire(M.core.event.FILTER_CONTENT_UPDATED,{nodes:d})})},notifyEditorContentRestored:function(){b.use("event","moodle-core-event",function(b){a(document).trigger(M.core.event.EDITOR_CONTENT_RESTORED),b.fire(M.core.event.EDITOR_CONTENT_RESTORED)})}}});

View File

@ -27,7 +27,14 @@ define(['jquery', 'core/yui'],
function($, Y) {
return /** @alias module:core/event */ {
// Public variables and functions.
// These are AMD only events - no backwards compatibility for new things.
Events: {
FORM_FIELD_VALIDATION: "core_form-field-validation"
},
/**
* Trigger an event using both JQuery and YUI
*

View File

@ -26,6 +26,7 @@
*/
require_once('HTML/QuickForm/advcheckbox.php');
require_once(__DIR__ . '/../outputcomponents.php');
/**
* HTML class for an advcheckbox type element
@ -38,7 +39,7 @@ require_once('HTML/QuickForm/advcheckbox.php');
* @copyright 2007 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_advcheckbox extends HTML_QuickForm_advcheckbox{
class MoodleQuickForm_advcheckbox extends HTML_QuickForm_advcheckbox implements templatable {
/** @var string html for help button, if empty then no help will icon will be dispalyed. */
var $_helpbutton='';
@ -130,4 +131,13 @@ class MoodleQuickForm_advcheckbox extends HTML_QuickForm_advcheckbox{
}
return $output;
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
return $context;
}
}

View File

@ -204,4 +204,23 @@ class MoodleQuickForm_autocomplete extends MoodleQuickForm_select {
}
return parent::onQuickFormEvent($event, $arg, $caller);
}
public function export_for_template(renderer_base $output) {
global $PAGE;
$this->_generateId();
$id = $this->getAttribute('id');
$PAGE->requires->js_call_amd('core/form-autocomplete', 'enhance', $params = array('#' . $id, $this->tags, $this->ajax,
$this->placeholder, $this->casesensitive, $this->showsuggestions, $this->noselectionstring));
$context = parent::export_for_template($output);
$context['tags'] = $this->tags;
$context['ajax'] = $this->ajax;
$context['placeholder'] = $this->placeholder;
$context['casesensitive'] = $this->casesensitive;
$context['showsuggestions'] = $this->showsuggestions;
$context['noselectionstring'] = $this->noselectionstring;
return $context;
}
}

View File

@ -26,6 +26,7 @@
*/
require_once("HTML/QuickForm/button.php");
require_once(__DIR__ . '/../outputcomponents.php');
/**
* HTML class for a button type element
@ -37,7 +38,7 @@ require_once("HTML/QuickForm/button.php");
* @copyright 2007 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_button extends HTML_QuickForm_button
class MoodleQuickForm_button extends HTML_QuickForm_button implements templatable
{
/** @var string html for help button, if empty then no help */
var $_helpbutton='';
@ -85,4 +86,13 @@ class MoodleQuickForm_button extends HTML_QuickForm_button
return 'default';
}
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
return $context;
}
}

View File

@ -26,6 +26,7 @@
*/
require_once('HTML/QuickForm/checkbox.php');
require_once(__DIR__ . '/../outputcomponents.php');
/**
* HTML class for a checkbox type element
@ -39,7 +40,7 @@ require_once('HTML/QuickForm/checkbox.php');
* @copyright 2007 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_checkbox extends HTML_QuickForm_checkbox{
class MoodleQuickForm_checkbox extends HTML_QuickForm_checkbox implements templatable {
/** @var string html for help button, if empty then no help */
var $_helpbutton='';
@ -138,4 +139,13 @@ class MoodleQuickForm_checkbox extends HTML_QuickForm_checkbox{
}
return $output;
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
return $context;
}
}

View File

@ -30,6 +30,7 @@ global $CFG;
require_once('HTML/QuickForm/element.php');
require_once($CFG->dirroot.'/lib/filelib.php');
require_once($CFG->dirroot.'/repository/lib.php');
require_once($CFG->libdir.'/outputcomponents.php');
/**
* Editor element
@ -43,7 +44,7 @@ require_once($CFG->dirroot.'/repository/lib.php');
* @todo MDL-29421 element Freezing
* @todo MDL-29426 ajax format conversion
*/
class MoodleQuickForm_editor extends HTML_QuickForm_element {
class MoodleQuickForm_editor extends HTML_QuickForm_element implements templatable {
/** @var string html for help button, if empty then no help will icon will be dispalyed. */
public $_helpbutton = '';
@ -293,7 +294,7 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element {
* @return string
*/
function toHtml() {
global $CFG, $PAGE;
global $CFG, $PAGE, $OUTPUT;
require_once($CFG->dirroot.'/repository/lib.php');
if ($this->_flagFrozen) {
@ -394,24 +395,27 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element {
$cols = empty($this->_attributes['cols']) ? 80 : $this->_attributes['cols'];
//Apply editor validation if required field
$editorrules = '';
if (!is_null($this->getAttribute('onblur')) && !is_null($this->getAttribute('onchange'))) {
$editorrules = ' onblur="'.htmlspecialchars($this->getAttribute('onblur')).'" onchange="'.htmlspecialchars($this->getAttribute('onchange')).'"';
$context = [];
$context['rows'] = $rows;
$context['cols'] = $cols;
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
$str .= '<div><textarea id="'.$id.'" name="'.$elname.'[text]" rows="'.$rows.'" cols="'.$cols.'" spellcheck="true"'.$editorrules.'>';
$str .= s($text);
$str .= '</textarea></div>';
$context['hasformats'] = count($formats) > 1;
$context['formats'] = [];
foreach ($formats as $value => $text) {
$context['formats'][] = ['value' => $value, 'text' => $text, 'selected' => ($value == $format)];
}
$context['id'] = $id;
$context['value'] = $text;
$context['format'] = $format;
$str .= '<div>';
if (count($formats)>1) {
$str .= html_writer::label(get_string('format'), 'menu'. $elname. 'format', false, array('class' => 'accesshide'));
$str .= html_writer::select($formats, $elname.'[format]', $format, false, array('id' => 'menu'. $elname. 'format'));
} else {
$keys = array_keys($formats);
$str .= html_writer::empty_tag('input',
array('name'=>$elname.'[format]', 'type'=> 'hidden', 'value' => array_pop($keys)));
$str .= $OUTPUT->render_from_template('core_form/editor_textarea', $context);
if (!is_null($this->getAttribute('onblur')) && !is_null($this->getAttribute('onchange'))) {
$context['changelistener'] = true;
}
$str .= '</div>';
// during moodle installation, user area doesn't exist
// so we need to disable filepicker here.
@ -446,6 +450,16 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element {
return $str;
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
$context['html'] = $this->toHtml();
return $context;
}
/**
* What to display when element is frozen.
*

View File

@ -30,6 +30,7 @@ global $CFG;
require_once('HTML/QuickForm/element.php');
require_once($CFG->dirroot.'/lib/filelib.php');
require_once($CFG->dirroot.'/repository/lib.php');
require_once($CFG->libdir.'/outputcomponents.php');
/**
* Filemanager form element
@ -40,7 +41,7 @@ require_once($CFG->dirroot.'/repository/lib.php');
* @copyright 2009 Dongsheng Cai <dongsheng@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_filemanager extends HTML_QuickForm_element {
class MoodleQuickForm_filemanager extends HTML_QuickForm_element implements templatable {
/** @var string html for help button, if empty then no help will icon will be dispalyed. */
public $_helpbutton = '';
@ -297,6 +298,16 @@ class MoodleQuickForm_filemanager extends HTML_QuickForm_element {
return $html;
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
$context['html'] = $this->toHtml();
return $context;
}
}
/**

View File

@ -29,6 +29,7 @@ global $CFG;
require_once("HTML/QuickForm/button.php");
require_once($CFG->dirroot.'/repository/lib.php');
require_once($CFG->libdir.'/outputcomponents.php');
/**
* Filepicker form element
@ -40,7 +41,7 @@ require_once($CFG->dirroot.'/repository/lib.php');
* @copyright 2009 Dongsheng Cai <dongsheng@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_filepicker extends HTML_QuickForm_input {
class MoodleQuickForm_filepicker extends HTML_QuickForm_input implements templatable {
/** @var string html for help button, if empty then no help will icon will be dispalyed. */
public $_helpbutton = '';
@ -220,4 +221,14 @@ class MoodleQuickForm_filepicker extends HTML_QuickForm_input {
return $this->_prepareValue($draftitemid, true);
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
$context['html'] = $this->toHtml();
return $context;
}
}

View File

@ -28,6 +28,7 @@
global $CFG;
require_once("HTML/QuickForm/element.php");
require_once($CFG->dirroot.'/grade/grading/form/lib.php');
require_once($CFG->libdir.'/outputcomponents.php');
if (class_exists('HTML_QuickForm')) {
HTML_QuickForm::registerRule('gradingvalidated', 'callback', '_validate', 'MoodleQuickForm_grading');
@ -47,7 +48,7 @@ if (class_exists('HTML_QuickForm')) {
* @copyright 2011 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_grading extends HTML_QuickForm_input{
class MoodleQuickForm_grading extends HTML_QuickForm_input implements templatable {
/** @var string html for help button, if empty then no help */
var $_helpbutton='';
@ -63,6 +64,7 @@ class MoodleQuickForm_grading extends HTML_QuickForm_input{
*/
public function __construct($elementName=null, $elementLabel=null, $attributes=null) {
parent::__construct($elementName, $elementLabel, $attributes);
$this->_type = 'grading';
$this->gradingattributes = $attributes;
}
@ -158,4 +160,8 @@ class MoodleQuickForm_grading extends HTML_QuickForm_input{
}
return true;
}
public function export_for_template(renderer_base $output) {
return $this->toHtml();
}
}

View File

@ -26,6 +26,7 @@
*/
require_once("HTML/QuickForm/group.php");
require_once(__DIR__ . '/../outputcomponents.php');
/**
* HTML class for a form element group
@ -37,13 +38,15 @@ require_once("HTML/QuickForm/group.php");
* @copyright 2007 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_group extends HTML_QuickForm_group{
class MoodleQuickForm_group extends HTML_QuickForm_group implements templatable {
/** @var string html for help button, if empty then no help */
var $_helpbutton='';
/** @var MoodleQuickForm */
protected $_mform = null;
var $_renderedfromtemplate = false;
/**
* constructor
*
@ -147,4 +150,89 @@ class MoodleQuickForm_group extends HTML_QuickForm_group{
}
return call_user_func_array([$this->_mform, 'createElement'], func_get_args());
}
public function export_for_template(renderer_base $output) {
global $OUTPUT;
$this->_renderedfromtemplate = true;
include_once('HTML/QuickForm/Renderer/Default.php');
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
$elements = [];
foreach ($this->_elements as $key => $element) {
$element->_generateId();
$name = $this->getName();
$elementname = '';
if ($this->_appendName) {
$elementname = $element->getName();
if (isset($elementname)) {
$element->setName($name . '['. (strlen($elementname) ? $elementname : $key) .']');
} else {
$element->setName($name);
}
}
$out = $OUTPUT->mform_element($element, false, '', true);
if (empty($out)) {
$renderer = new HTML_QuickForm_Renderer_Default();
$renderer->setElementTemplate('{element}');
$element->accept($renderer);
$out = $renderer->toHtml();
}
$elements[] = $out;
// Restore the element's name.
if ($this->_appendName) {
$element->setName($elementname);
}
}
$context['elements'] = $elements;
return $context;
}
/**
* Accepts a renderer
*
* @param object An HTML_QuickForm_Renderer object
* @param bool Whether a group is required
* @param string An error message associated with a group
* @access public
* @return void
*/
function accept(&$renderer, $required = false, $error = null) {
$this->_createElementsIfNotExist();
$renderer->startGroup($this, $required, $error);
if (!$this->_renderedfromtemplate) {
// Backwards compatible path - only do this if we didn't render the sub-elements already.
$name = $this->getName();
foreach (array_keys($this->_elements) as $key) {
$element =& $this->_elements[$key];
if ($this->_appendName) {
$elementName = $element->getName();
if (isset($elementName)) {
$element->setName($name . '['. (strlen($elementName)? $elementName: $key) .']');
} else {
$element->setName($name);
}
}
$required = !$element->isFrozen() && in_array($element->getName(), $this->_required);
$element->accept($renderer, $required);
// restore the element's name
if ($this->_appendName) {
$element->setName($elementName);
}
}
}
$renderer->finishGroup($this);
}
}

View File

@ -149,14 +149,14 @@ class MoodleQuickForm_modgrade extends MoodleQuickForm_group {
$langscale = get_string('modgradetypescale', 'grades');
$this->scaleformelement = $this->createFormElement('select', 'modgrade_scale', $langscale,
$scales, $attributes);
$this->scaleformelement->setHiddenLabel = false;
$this->scaleformelement->setHiddenLabel(true);
$scaleformelementid = $this->generate_modgrade_subelement_id('modgrade_scale');
$this->scaleformelement->updateAttributes(array('id' => $scaleformelementid));
// Maximum grade textbox.
$langmaxgrade = get_string('modgrademaxgrade', 'grades');
$this->maxgradeformelement = $this->createFormElement('text', 'modgrade_point', $langmaxgrade, array());
$this->maxgradeformelement->setHiddenLabel = false;
$this->maxgradeformelement->setHiddenLabel(true);
$maxgradeformelementid = $this->generate_modgrade_subelement_id('modgrade_point');
$this->maxgradeformelement->updateAttributes(array('id' => $maxgradeformelementid));
@ -169,7 +169,7 @@ class MoodleQuickForm_modgrade extends MoodleQuickForm_group {
$langtype = get_string('modgradetype', 'grades');
$this->gradetypeformelement = $this->createFormElement('select', 'modgrade_type', $langtype, $gradetype,
$attributes, true);
$this->gradetypeformelement->setHiddenLabel = false;
$this->gradetypeformelement->setHiddenLabel(true);
$gradetypeformelementid = $this->generate_modgrade_subelement_id('modgrade_type');
$this->gradetypeformelement->updateAttributes(array('id' => $gradetypeformelementid));
@ -188,7 +188,7 @@ class MoodleQuickForm_modgrade extends MoodleQuickForm_group {
'modgrade_rescalegrades',
$langrescalegrades,
$choices);
$rescalegradesselect->setHiddenLabel = false;
$rescalegradesselect->setHiddenLabel(true);
$rescalegradesselectid = $this->generate_modgrade_subelement_id('modgrade_rescalegrades');
$rescalegradesselect->updateAttributes(array('id' => $rescalegradesselectid));
}

View File

@ -26,6 +26,7 @@
*/
require_once('HTML/QuickForm/password.php');
require_once(__DIR__ . '/../outputcomponents.php');
/**
* Password type form element
@ -37,7 +38,7 @@ require_once('HTML/QuickForm/password.php');
* @copyright 2006 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_password extends HTML_QuickForm_password{
class MoodleQuickForm_password extends HTML_QuickForm_password implements templatable {
/** @var string, html for help button, if empty then no help */
var $_helpbutton='';
@ -83,4 +84,13 @@ class MoodleQuickForm_password extends HTML_QuickForm_password{
function getHelpButton(){
return $this->_helpbutton;
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
return $context;
}
}

View File

@ -26,6 +26,7 @@
*/
require_once('HTML/QuickForm/input.php');
require_once(__DIR__ . '/../outputcomponents.php');
/**
* recaptcha type form element
@ -37,7 +38,7 @@ require_once('HTML/QuickForm/input.php');
* @copyright 2008 Nicolas Connault <nicolasconnault@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_recaptcha extends HTML_QuickForm_input {
class MoodleQuickForm_recaptcha extends HTML_QuickForm_input implements templatable {
/** @var string html for help button, if empty then no help */
var $_helpbutton='';
@ -152,4 +153,14 @@ class MoodleQuickForm_recaptcha extends HTML_QuickForm_input {
}
return true;
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
$context['html'] = $this->toHtml();
return $context;
}
}

View File

@ -26,6 +26,7 @@
*/
require_once('HTML/QuickForm/select.php');
require_once(__DIR__ . '/../outputcomponents.php');
/**
* select type form element
@ -37,7 +38,7 @@ require_once('HTML/QuickForm/select.php');
* @copyright 2006 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_select extends HTML_QuickForm_select{
class MoodleQuickForm_select extends HTML_QuickForm_select implements templatable {
/** @var string html for help button, if empty then no help */
var $_helpbutton='';
@ -189,4 +190,33 @@ class MoodleQuickForm_select extends HTML_QuickForm_select{
return $this->_prepareValue($cleaned[0], $assoc);
}
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
$context['attributes'] = [];
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
if (!in_array($name, ['id', 'name', 'multiple'])) {
$context['attributes'][] = ['name' => $name, 'value' => $value];
}
}
$options = [];
foreach ($this->_options as $option) {
if (is_array($this->_values) && in_array( (string) $option['attr']['value'], $this->_values)) {
$this->_updateAttrArray($option['attr'], ['selected' => 'selected']);
}
$o = [
'text' => $option['text'],
'value' => $option['attr']['value'],
'selected' => !empty($option['attr']['selected'])
];
$options[] = $o;
}
$context['options'] = $options;
$context['hideLabel'] = $this->_hiddenLabel;
return $context;
}
}

View File

@ -26,6 +26,7 @@
*/
require_once('HTML/QuickForm/element.php');
require_once(__DIR__ . '/../outputcomponents.php');
/**
* select type form element
@ -37,7 +38,7 @@ require_once('HTML/QuickForm/element.php');
* @copyright 2007 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_selectgroups extends HTML_QuickForm_element {
class MoodleQuickForm_selectgroups extends HTML_QuickForm_element implements templatable {
/** @var bool add choose option */
var $showchoose = false;
@ -507,4 +508,48 @@ class MoodleQuickForm_selectgroups extends HTML_QuickForm_element {
return 'default';
}
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
$context['attributes'] = [];
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
if (!in_array($name, ['id', 'name', 'multiple'])) {
$context['attributes'][] = ['name' => $name, 'value' => $value];
}
}
$optiongroups = [];
if ($this->showchoose) {
$optionsgroups[] = [
'text' => get_string('choosedots')
];
}
foreach ($this->_optGroups as $group) {
$options = [];
foreach ($group['options'] as $option) {
$o = [];
if (is_array($this->_values) && in_array((string)$option['attr']['value'], $this->_values)) {
$o['selected'] = true;
} else {
$o['selected'] = false;
}
$o['text'] = $option['text'];
$options[] = $o;
}
$og = [
'text' => $group['attr']['label'],
'options' => $options
];
$optiongroups[] = $og;
}
$context['optiongroups'] = $optiongroups;
$context['hideLabel'] = $this->_hiddenLabel;
return $context;
}
}

View File

@ -32,6 +32,7 @@ require_once('HTML/QuickForm/select.php');
*
* HTML class for a select type element with options containing link
*
* @deprecated since 3.2
* @package core_form
* @category form
* @copyright 2008 Nicolas Connault <nicolasconnault@gmail.com>
@ -63,6 +64,7 @@ class MoodleQuickForm_selectwithlink extends HTML_QuickForm_select{
* @param bool $linkdata data to be posted
*/
public function __construct($elementName=null, $elementLabel=null, $options=null, $attributes=null, $linkdata=null) {
debugging('Element type selectwithlink is deprecated. Use 2 elements.', DEBUG_DEVELOPER);
if (!empty($linkdata['link']) && !empty($linkdata['label'])) {
$this->_link = $linkdata['link'];
$this->_linklabel = $linkdata['label'];

View File

@ -26,6 +26,7 @@
*/
require_once("HTML/QuickForm/static.php");
require_once(__DIR__ . '/../outputcomponents.php');
/**
* Text type element
@ -37,7 +38,7 @@ require_once("HTML/QuickForm/static.php");
* @copyright 2006 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_static extends HTML_QuickForm_static{
class MoodleQuickForm_static extends HTML_QuickForm_static implements templatable {
/** @var string Form element type */
var $_elementTemplateType='static';
@ -82,4 +83,14 @@ class MoodleQuickForm_static extends HTML_QuickForm_static{
function getElementTemplateType(){
return $this->_elementTemplateType;
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
$context['html'] = $this->toHtml();
return $context;
}
}

View File

@ -26,6 +26,7 @@
*/
require_once("HTML/QuickForm/submit.php");
require_once(__DIR__ . '/../outputcomponents.php');
/**
* submit type form element
@ -37,7 +38,7 @@ require_once("HTML/QuickForm/submit.php");
* @copyright 2006 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_submit extends HTML_QuickForm_submit {
class MoodleQuickForm_submit extends HTML_QuickForm_submit implements templatable {
/**
* constructor
*
@ -108,4 +109,15 @@ class MoodleQuickForm_submit extends HTML_QuickForm_submit {
$this->_flagFrozen = true;
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
if ($this->getName() == 'cancel') {
$context['iscancel'] = true;
}
return $context;
}
}

View File

@ -20,6 +20,7 @@
*
* Contains HTML class for a submitting to link
*
* @deprecated since 3.2
* @package core_form
* @copyright 2006 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@ -52,6 +53,7 @@ class MoodleQuickForm_submitlink extends MoodleQuickForm_submit {
* @param string $attributes (optional) Either a typical HTML attribute string or an associative array
*/
public function __construct($elementName=null, $value=null, $attributes=null) {
debugging('Element type submitlink is deprecated.', DEBUG_DEVELOPER);
parent::__construct($elementName, $value, $attributes);
}

View File

@ -0,0 +1,16 @@
<div>
<textarea id="{{id}}" name="{{name}}[text]" rows="{{rows}}" cols="{{cols}}" spellcheck="true" {{#changelistener}} onblur="{{onblur}}"
onchange="{{onchange}}" {{/changelistener}}>{{text}}</textarea>
</div>
<div>
{{^onlyoneformat}}
<select name="{{name}}[format]" id="menu{{name}}format">
{{#formats}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{text}}</option>
{{/formats}}
</select>
{{/onlyoneformat}}
{{#onlyoneformat}}
<input name="{{name}}[format]" type="hidden" value="{{format}}"/>
{{/onlyoneformat}}
</div>

View File

@ -26,6 +26,7 @@
*/
require_once("HTML/QuickForm/text.php");
require_once(__DIR__ . '/../outputcomponents.php');
/**
* Text type form element
@ -37,7 +38,8 @@ require_once("HTML/QuickForm/text.php");
* @copyright 2006 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_text extends HTML_QuickForm_text{
class MoodleQuickForm_text extends HTML_QuickForm_text implements templatable {
/** @var string html for help button, if empty then no help */
var $_helpbutton='';
@ -124,4 +126,14 @@ class MoodleQuickForm_text extends HTML_QuickForm_text{
function getHelpButton(){
return $this->_helpbutton;
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
$context['hideLabel'] = $this->_hiddenLabel;
return $context;
}
}

View File

@ -26,6 +26,7 @@
*/
require_once('HTML/QuickForm/textarea.php');
require_once(__DIR__ . '/../outputcomponents.php');
/**
* Textarea type form element
@ -37,7 +38,7 @@ require_once('HTML/QuickForm/textarea.php');
* @copyright 2006 Jamie Pratt <me@jamiep.org>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_textarea extends HTML_QuickForm_textarea{
class MoodleQuickForm_textarea extends HTML_QuickForm_textarea implements templatable {
/** @var string Need to store id of form as we may need it for helpbutton */
var $_formid = '';
@ -130,4 +131,14 @@ class MoodleQuickForm_textarea extends HTML_QuickForm_textarea{
return 'default';
}
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
$context['hideLabel'] = $this->_hiddenLabel;
return $context;
}
}

View File

@ -26,6 +26,7 @@
*/
require_once("HTML/QuickForm/text.php");
require_once(__DIR__ . '/../outputcomponents.php');
/**
* url type form element
@ -36,7 +37,7 @@ require_once("HTML/QuickForm/text.php");
* @copyright 2009 Dongsheng Cai <dongsheng@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_url extends HTML_QuickForm_text{
class MoodleQuickForm_url extends HTML_QuickForm_text implements templatable {
/** @var string html for help button, if empty then no help */
var $_helpbutton='';
@ -61,7 +62,9 @@ class MoodleQuickForm_url extends HTML_QuickForm_text{
if (!isset($this->_options['usefilepicker'])) {
$this->_options['usefilepicker'] = true;
}
parent::__construct($elementName, $elementLabel, $attributes);
$this->_type = 'url';
}
/**
@ -89,7 +92,7 @@ class MoodleQuickForm_url extends HTML_QuickForm_text{
* @return string
*/
function toHtml(){
global $PAGE, $OUTPUT;
$id = $this->_attributes['id'];
$elname = $this->_attributes['name'];
@ -105,6 +108,16 @@ class MoodleQuickForm_url extends HTML_QuickForm_text{
return $str;
}
// print out file picker
$str .= $this->getFilePickerHTML();
return $str;
}
function getFilePickerHTML() {
global $PAGE, $OUTPUT;
$str = '';
$client_id = uniqid();
$args = new stdClass();
@ -119,7 +132,7 @@ class MoodleQuickForm_url extends HTML_QuickForm_text{
if (count($options->repositories) > 0) {
$straddlink = get_string('choosealink', 'repository');
$str .= <<<EOD
<button id="filepicker-button-js-{$client_id}" class="visibleifjs">
<button id="filepicker-button-js-{$client_id}" class="visibleifjs btn btn-secondary">
$straddlink
</button>
EOD;
@ -157,4 +170,14 @@ EOD;
return 'default';
}
}
public function export_for_template(renderer_base $output) {
$context = [];
$context['frozen'] = $this->_flagFrozen;
foreach ($this->getAttributes() as $name => $value) {
$context[$name] = $value;
}
$context['filepickerhtml'] = $this->getFilePickerHTML();
return $context;
}
}

View File

@ -2091,6 +2091,8 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
*/
function getValidationScript()
{
global $PAGE;
if (empty($this->_rules) || $this->clientvalidation === false) {
return '';
}
@ -2170,67 +2172,74 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
unset($element);
$js = '
<script type="text/javascript">
//<![CDATA[
var skipClientValidation = false;
(function() {
require(["core/event", "jquery"], function(Event, $) {
function qf_errorHandler(element, _qfMsg, escapedName) {
div = element.parentNode;
var event = $.Event(Event.Events.FORM_FIELD_VALIDATION);
$(element).trigger(event, _qfMsg);
if (event.isDefaultPrevented()) {
return _qfMsg == \'\';
} else {
// Legacy mforms.
var div = element.parentNode;
if ((div == undefined) || (element.name == undefined)) {
//no checking can be done for undefined elements so let server handle it.
return true;
}
if ((div == undefined) || (element.name == undefined)) {
// No checking can be done for undefined elements so let server handle it.
return true;
}
if (_qfMsg != \'\') {
var errorSpan = document.getElementById(\'id_error_\' + escapedName);
if (!errorSpan) {
errorSpan = document.createElement("span");
errorSpan.id = \'id_error_\' + escapedName;
errorSpan.className = "error";
element.parentNode.insertBefore(errorSpan, element.parentNode.firstChild);
document.getElementById(errorSpan.id).setAttribute(\'TabIndex\', \'0\');
document.getElementById(errorSpan.id).focus();
}
if (_qfMsg != \'\') {
var errorSpan = document.getElementById(\'id_error_\' + escapedName);
if (!errorSpan) {
errorSpan = document.createElement("span");
errorSpan.id = \'id_error_\' + escapedName;
errorSpan.className = "error";
element.parentNode.insertBefore(errorSpan, element.parentNode.firstChild);
document.getElementById(errorSpan.id).setAttribute(\'TabIndex\', \'0\');
document.getElementById(errorSpan.id).focus();
}
while (errorSpan.firstChild) {
errorSpan.removeChild(errorSpan.firstChild);
}
while (errorSpan.firstChild) {
errorSpan.removeChild(errorSpan.firstChild);
}
errorSpan.appendChild(document.createTextNode(_qfMsg.substring(3)));
errorSpan.appendChild(document.createTextNode(_qfMsg.substring(3)));
if (div.className.substr(div.className.length - 6, 6) != " error"
&& div.className != "error") {
div.className += " error";
linebreak = document.createElement("br");
linebreak.className = "error";
linebreak.id = \'id_error_break_\' + escapedName;
errorSpan.parentNode.insertBefore(linebreak, errorSpan.nextSibling);
}
if (div.className.substr(div.className.length - 6, 6) != " error"
&& div.className != "error") {
div.className += " error";
linebreak = document.createElement("br");
linebreak.className = "error";
linebreak.id = \'id_error_break_\' + escapedName;
errorSpan.parentNode.insertBefore(linebreak, errorSpan.nextSibling);
}
return false;
} else {
var errorSpan = document.getElementById(\'id_error_\' + escapedName);
if (errorSpan) {
errorSpan.parentNode.removeChild(errorSpan);
}
var linebreak = document.getElementById(\'id_error_break_\' + escapedName);
if (linebreak) {
linebreak.parentNode.removeChild(linebreak);
}
return false;
} else {
var errorSpan = document.getElementById(\'id_error_\' + escapedName);
if (errorSpan) {
errorSpan.parentNode.removeChild(errorSpan);
}
var linebreak = document.getElementById(\'id_error_break_\' + escapedName);
if (linebreak) {
linebreak.parentNode.removeChild(linebreak);
}
if (div.className.substr(div.className.length - 6, 6) == " error") {
div.className = div.className.substr(0, div.className.length - 6);
} else if (div.className == "error") {
div.className = "";
}
if (div.className.substr(div.className.length - 6, 6) == " error") {
div.className = div.className.substr(0, div.className.length - 6);
} else if (div.className == "error") {
div.className = "";
}
return true;
}
}';
return true;
} // End if.
} // End if.
} // End function.
';
$validateJS = '';
foreach ($test as $elementName => $jsandelement) {
// Fix for bug displaying errors for elements in a group
@ -2323,10 +2332,12 @@ var skipClientValidation = false;
ev.preventDefault();
}
});
})();
//]]>
</script>';
return $js;
});
';
$PAGE->requires->js_amd_inline($js);
return '';
} // end func getValidationScript
/**
@ -2753,6 +2764,8 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
* @param string $error error message to display
*/
function startGroup(&$group, $required, $error){
global $OUTPUT;
// Make sure the element has an id.
$group->_generateId();
@ -2762,47 +2775,50 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
// Update the ID.
$group->updateAttributes(array('id' => $groupid));
if (method_exists($group, 'getElementTemplateType')){
$html = $this->_elementTemplates[$group->getElementTemplateType()];
}else{
$html = $this->_elementTemplates['default'];
$html = $OUTPUT->mform_element($group, $required, $error, false);
$fromtemplate = !empty($html);
if (!$fromtemplate) {
if (method_exists($group, 'getElementTemplateType')) {
$html = $this->_elementTemplates[$group->getElementTemplateType()];
} else {
$html = $this->_elementTemplates['default'];
}
if (isset($this->_advancedElements[$group->getName()])) {
$html = str_replace(' {advanced}', ' advanced', $html);
$html = str_replace('{advancedimg}', $this->_advancedHTML, $html);
} else {
$html = str_replace(' {advanced}', '', $html);
$html = str_replace('{advancedimg}', '', $html);
}
if (method_exists($group, 'getHelpButton')) {
$html = str_replace('{help}', $group->getHelpButton(), $html);
} else {
$html = str_replace('{help}', '', $html);
}
$html = str_replace('{id}', $group->getAttribute('id'), $html);
$html = str_replace('{name}', $group->getName(), $html);
$html = str_replace('{type}', 'fgroup', $html);
$html = str_replace('{class}', $group->getAttribute('class'), $html);
$emptylabel = '';
if ($group->getLabel() == '') {
$emptylabel = 'femptylabel';
}
$html = str_replace('{emptylabel}', $emptylabel, $html);
}
if (isset($this->_advancedElements[$group->getName()])){
$html =str_replace(' {advanced}', ' advanced', $html);
$html =str_replace('{advancedimg}', $this->_advancedHTML, $html);
} else {
$html =str_replace(' {advanced}', '', $html);
$html =str_replace('{advancedimg}', '', $html);
}
if (method_exists($group, 'getHelpButton')){
$html =str_replace('{help}', $group->getHelpButton(), $html);
}else{
$html =str_replace('{help}', '', $html);
}
$html = str_replace('{id}', $group->getAttribute('id'), $html);
$html =str_replace('{name}', $group->getName(), $html);
$html =str_replace('{type}', 'fgroup', $html);
$html =str_replace('{fieldtype}', 'group', $html);
$html =str_replace('{class}', $group->getAttribute('class'), $html);
$emptylabel = '';
if ($group->getLabel() == '') {
$emptylabel = 'femptylabel';
}
$html = str_replace('{emptylabel}', $emptylabel, $html);
$this->_templates[$group->getName()]=$html;
$this->_templates[$group->getName()] = $html;
// Fix for bug in tableless quickforms that didn't allow you to stop a
// fieldset before a group of elements.
// if the element name indicates the end of a fieldset, close the fieldset
if ( in_array($group->getName(), $this->_stopFieldsetElements)
&& $this->_fieldsetsOpen > 0
) {
if (in_array($group->getName(), $this->_stopFieldsetElements) && $this->_fieldsetsOpen > 0) {
$this->_html .= $this->_closeFieldsetTemplate;
$this->_fieldsetsOpen--;
}
parent::startGroup($group, $required, $error);
if (!$fromtemplate) {
parent::startGroup($group, $required, $error);
} else {
$this->_html .= $html;
}
}
/**
@ -2813,56 +2829,66 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
* @param string $error error message to display
*/
function renderElement(&$element, $required, $error){
global $OUTPUT;
// Make sure the element has an id.
$element->_generateId();
//adding stuff to place holders in template
//check if this is a group element first
if (($this->_inGroup) and !empty($this->_groupElementTemplate)) {
// so it gets substitutions for *each* element
$html = $this->_groupElementTemplate;
}
elseif (method_exists($element, 'getElementTemplateType')){
$html = $this->_elementTemplates[$element->getElementTemplateType()];
}else{
$html = $this->_elementTemplates['default'];
}
if (isset($this->_advancedElements[$element->getName()])){
$html = str_replace(' {advanced}', ' advanced', $html);
$html = str_replace(' {aria-live}', ' aria-live="polite"', $html);
$html = $OUTPUT->mform_element($element, $required, $error, false);
$fromtemplate = !empty($html);
if (!$fromtemplate) {
// Adding stuff to place holders in template
// check if this is a group element first.
if (($this->_inGroup) and !empty($this->_groupElementTemplate)) {
// So it gets substitutions for *each* element.
$html = $this->_groupElementTemplate;
} else if (method_exists($element, 'getElementTemplateType')){
$html = $this->_elementTemplates[$element->getElementTemplateType()];
} else {
$html = $this->_elementTemplates['default'];
}
if (isset($this->_advancedElements[$element->getName()])){
$html = str_replace(' {advanced}', ' advanced', $html);
$html = str_replace(' {aria-live}', ' aria-live="polite"', $html);
} else {
$html = str_replace(' {advanced}', '', $html);
$html = str_replace(' {aria-live}', '', $html);
}
if (isset($this->_advancedElements[$element->getName()]) || $element->getName() == 'mform_showadvanced'){
$html = str_replace('{advancedimg}', $this->_advancedHTML, $html);
} else {
$html = str_replace('{advancedimg}', '', $html);
}
$html = str_replace('{id}', 'fitem_' . $element->getAttribute('id'), $html);
$html = str_replace('{type}', 'f' . $element->getType(), $html);
$html = str_replace('{name}', $element->getName(), $html);
$html = str_replace('{class}', $element->getAttribute('class'), $html);
$emptylabel = '';
if ($element->getLabel() == '') {
$emptylabel = 'femptylabel';
}
$html = str_replace('{emptylabel}', $emptylabel, $html);
if (method_exists($element, 'getHelpButton')) {
$html = str_replace('{help}', $element->getHelpButton(), $html);
} else {
$html = str_replace('{help}', '', $html);
}
} else {
$html = str_replace(' {advanced}', '', $html);
$html = str_replace(' {aria-live}', '', $html);
}
if (isset($this->_advancedElements[$element->getName()])||$element->getName() == 'mform_showadvanced'){
$html =str_replace('{advancedimg}', $this->_advancedHTML, $html);
} else {
$html =str_replace('{advancedimg}', '', $html);
}
$html =str_replace('{id}', 'fitem_' . $element->getAttribute('id'), $html);
$html =str_replace('{type}', 'f'.$element->getType(), $html);
$html =str_replace('{fieldtype}', $element->getType(), $html);
$html =str_replace('{name}', $element->getName(), $html);
$html =str_replace('{class}', $element->getAttribute('class'), $html);
$emptylabel = '';
if ($element->getLabel() == '') {
$emptylabel = 'femptylabel';
}
$html = str_replace('{emptylabel}', $emptylabel, $html);
if (method_exists($element, 'getHelpButton')){
$html = str_replace('{help}', $element->getHelpButton(), $html);
}else{
$html = str_replace('{help}', '', $html);
if ($this->_inGroup) {
$this->_groupElementTemplate = $html;
}
}
if (($this->_inGroup) and !empty($this->_groupElementTemplate)) {
$this->_groupElementTemplate = $html;
}
elseif (!isset($this->_templates[$element->getName()])) {
} else if (!isset($this->_templates[$element->getName()])) {
$this->_templates[$element->getName()] = $html;
}
parent::renderElement($element, $required, $error);
if (!$fromtemplate) {
parent::renderElement($element, $required, $error);
} else { // CRAZZY!
$this->_html .= $html;
}
}
/**

View File

@ -4421,6 +4421,51 @@ EOD;
return $this->render_from_template('core/login', $context);
}
/**
* Renders an mform element from a template.
*
* @param HTML_QuickForm_element $element element
* @param bool $required if input is required field
* @param string $error error message to display
* @param bool $ingroup True if this element is rendered as part of a group
* @return mixed string|bool
*/
public function mform_element($element, $required, $error, $ingroup) {
$templatename = 'core_form/element-' . $element->getType();
if ($ingroup) {
$templatename .= "-inline";
}
try {
// We call this to generate a file not found exception if there is no template.
// We don't want to call export_for_template if there is no template.
core\output\mustache_template_finder::get_template_filepath($templatename);
if ($element instanceof templatable) {
$elementcontext = $element->export_for_template($this);
$helpbutton = '';
if (method_exists($element, 'getHelpButton')) {
$helpbutton = $element->getHelpButton();
}
$label = $element->getLabel();
if (method_exists($element, 'getText')) {
$label .= ' ' . $element->getText();
}
$context = array(
'element' => $elementcontext,
'label' => $label,
'required' => $required,
'helpbutton' => $helpbutton,
'error' => $error
);
return $this->render_from_template($templatename, $context);
}
} catch (Exception $e) {
// No template for this element.
return false;
}
}
}
/**

View File

@ -157,10 +157,17 @@ a.autolink.glossary:hover {
.pagingbar .thispage {
font-weight: bold;
}
img.userpicture {
margin-right: 0.5rem;
}
img.resize {
height: 1em;
width: 1em;
}
.action-menu .dropdown-toggle {
margin-right: 0.5rem;
text-decoration: none;
}
.action-menu {
white-space: nowrap;
}
@ -168,6 +175,8 @@ img.resize {
width: 16px;
height: 16px;
box-sizing: content-box;
}
.action-menu .dropdown-menu img {
padding-right: 0.5rem;
}
.action-menu .userpicture {

View File

@ -1,5 +1,10 @@
/* course.less */
/* COURSE CONTENT */
.section-modchooser-link img {
margin-right: 0.5rem;
width: 16px;
height: 16px;
}
.section_add_menus {
text-align: right;
clear: both;

View File

@ -5,25 +5,12 @@
*
*/
form {
margin: 0;
}
.mform fieldset .advancedbutton {
text-align: right;
}
.jsenabled .mform .containsadvancedelements .advanced {
display: none;
}
.mform .containsadvancedelements .advanced.show {
display: block;
}
.mform fieldset.group {
margin-bottom: 0
}
.mform fieldset.error {
border: 1px solid $state-danger-text;
}
.mform span.error,
#adminsettings span.error {
display: inline-block;
border: 1px solid $state-danger-border;
@ -47,37 +34,9 @@ form {
.jsenabled .mform .collapsed .fcontainer {
display: none;
}
.mform .fitem .fitemtitle div {
display: inline;
}
#adminsettings .error,
.mform .error {
#adminsettings .error {
color: $state-danger-text;
}
.mform .fdescription.required {
margin-left: $display1-size;
}
.mform .fpassword .unmask {
display: inline-block;
margin-left: 0.5em;
& > input {
margin: 0;
}
& > label {
display: inline-block;
}
}
.mform label {
display: inline-block;
}
.mform .iconhelp {
margin-left: 4px;
}
.mform .ftextarea #id_alltext {
width: 100%;
}
.mform ul.file-list {
padding: 0;
margin: 0;
@ -87,39 +46,6 @@ form {
.mform label .adv {
cursor: help;
}
.mform .fcheckbox input {
margin-left: 0;
}
.mform .fcheckbox > span,
.mform .fradio > span,
.mform .fgroup > span {
display: inline-block;
margin-top: 5px;
}
.mform .fitem fieldset.fgroup label,
.mform fieldset.fdate_selector label {
display: inline;
float: none;
width: auto;
}
.mform .ftags label.accesshide {
display: block;
position: static;
}
.mform .ftags select {
margin-bottom: 0.7em;
min-width: 22em;
}
.mform .helplink img {
margin: 0 .45em;
padding: 0;
}
.mform legend .helplink img {
margin: 0 .2em;
}
.singleselect label {
margin-right: .3em;
}
/*rtl:ignore*/
input#id_externalurl {
direction: ltr;
@ -129,8 +55,7 @@ input#id_externalurl {
}
// Copying in Bootstrap styles.
.form-item,
.mform .fitem {
.form-item {
margin-bottom: 10px;
// Theres's a mysterious extra 10px inside this item,
// so reduce margin by 10px from 20px standard to compensate.
@ -145,7 +70,6 @@ input#id_externalurl {
}
.form-item .form-setting,
.form-item .form-description,
.mform .fitem .felement,
#page-mod-forum-search .c1 .form-horizontal {
@extend .controls;
}
@ -159,14 +83,14 @@ input#id_externalurl {
// uneditable looks ugly, styling both as form help is fairly
// subtle in it's impact. Going for the latter as the best option.
.form-item .form-description,
.felement.fstatic {
.no-felement.fstatic {
@extend .text-muted;
padding-top: 5px;
}
.form-item .form-description {
padding-top: 0;
}
.fitem .fstaticlabel {
.no-fitem .fstaticlabel {
font-weight: bold;
}
@ -204,11 +128,6 @@ div.backup-section + form,
border: 0;
border-bottom: 1px solid #e5e5e5;
}
.mform legend a,
.mform legend a:hover {
color: $body-color;
text-decoration: none;
}
// I think this could be avoided (or at least tidied up) ifr
// we used HTML5 input types like url, phone, email, number etc.
@ -306,32 +225,9 @@ div.backup-section + form,
display: inline-block;
}
// Checkbox labels. Bootstrap puts the associated checkbox inside the label.
// Moodle puts it beside the label, so we need to make it inline-block
// to keep it on the same horizontal level.
input[type="radio"] + label,
input[type="checkbox"] + label {
display: inline;
padding-left: 0.2em;
}
input[type="radio"],
input[type="checkbox"] {
margin-top: -4px; // Dodgy hack, must be better way.
margin-right: 7px;
}
.singleselect {
display: inline-block;
form,
select{
margin: 0;
}
}
.form-item .form-label label {
margin-bottom: 0;
}
.felement.ffilepicker {
margin-top: 5px;
}
div#dateselector-calendar-panel {
z-index: 3100; /* Set higher than the z-index of the filemanager - see MDL-39047. */
}
@ -343,88 +239,7 @@ fieldset.coursesearchbox label {
/**
* Show the labels above text editors and file managers except on wide screens.
*/
#region-main .mform:not(.unresponsive) .fitem .fitemtitle label {
font-weight: bold;
}
@mixin makeFormsVertical() {
#region-main .mform:not(.unresponsive) {
.fitem {
.fitemtitle {
display: block;
margin-top: 4px;
margin-bottom: 4px;
text-align: left;
width: 100%;
}
.felement {
margin-left: 0;
width: 100%;
float: left;
padding-left: 0;
padding-right: 0;
}
.fstatic:empty {
display: none;
}
.fcheckbox > span,
.fradio > span,
.fgroup > span {
margin-top: 4px;
}
}
.femptylabel {
.fitemtitle {
display: inline-block;
width: auto;
margin-right: 8px;
}
.felement {
display: inline-block;
margin-top: 4px;
padding-top: 5px;
width: auto;
}
}
.fitem_fcheckbox{
.fitemtitle,
.felement {
display: inline-block;
width: auto;
}
.felement {
padding: 6px;
}
}
}
}
/**
* Make forms vertical when the screen is less than 1200px;
*/
@media (max-width: 1199px) {
body {
@include makeFormsVertical();
}
}
/**
* Make forms vertical when the screen is less than 1474px AND both side-pre and side-post contain blocks.
* This is an extra special media rule.
* It causes forms to show vertically when the screen size is calculated as:
* 1199px + (1199px * 23%)
* Where 23% is the width of span3
* Full calculation is:
* $maxWidthForVerticalForms: 1199px * (unit((($fluidGridColumnWidth1200 * 3) + ($fluidGridGutterWidth * (3 - 1)))) / 100) + 1199px;
*/
$maxWidthForVerticalForms: 1474px;
@media (max-width: $maxWidthForVerticalForms) {
.used-region-side-pre.used-region-side-post {
@include makeFormsVertical();
}
}
/* Section and module editing forms contain special JS components for the
availability system (if enabled). */
@ -538,13 +353,6 @@ $maxWidthForVerticalForms: 1474px;
}
}
/* Revert to the non-fixed width where a textarea has the number of columns
specified, or an input has it's size specified. */
textarea[cols],
input[size] {
width: auto;
}
/* Custom styles for autocomplete form element */
.form-autocomplete-selection {
margin: 0.2em;
@ -564,7 +372,7 @@ input[size] {
overflow: auto;
margin: 0px;
padding: 0px;
margin-top: -0.2em;
margin-top: 0.4em;
z-index: 1;
}
.form-autocomplete-suggestions li {
@ -586,7 +394,7 @@ input[size] {
.form-autocomplete-downarrow {
color: $body-color;
position: relative;
top: -0.3em;
top: 0.2em;
left: -1.5em;
cursor: pointer;
}
@ -598,3 +406,7 @@ input[size] {
padding: 0.5em;
font-size: large;
}
select[multiple] {
overflow: auto;
}

View File

@ -0,0 +1,43 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core/form_autocomplete_input
Moodle template for the input field in an autocomplate form element.
Classes required for JS:
* none
Data attributes required for JS:
* none
Context variables required for this template:
* inputId The dom id of this input field.
* suggestionsId The dom id of the suggestions list.
* selectionId The dom id of the current selection list.
* downArrowId The dom id of the down arrow to open the suggestions.
* placeholder The place holder text when the field is empty
Example context (json):
{ "inputID": 1, "suggestionsId": 2, "selectionId": 3, "downArrowId": 4, "placeholder": "Select something" }
}}
{{#showSuggestions}}
<input type="text" id="{{inputId}}" class="form-control col-md-4" list="{{suggestionsId}}" placeholder="{{placeholder}}" role="combobox" aria-expanded="false" autocomplete="off" autocorrect="off" autocapitalize="off" aria-autocomplete="list" aria-owns="{{suggestionsId}} {{selectionId}}"/><span class="form-autocomplete-downarrow" id="{{downArrowId}}">&#x25BC;</span>
{{/showSuggestions}}
{{^showSuggestions}}
<input type="text" id="{{inputId}}" placeholder="{{placeholder}}" role="textbox" aria-owns="{{selectionId}}"/>
{{/showSuggestions}}

View File

@ -0,0 +1,51 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core/form_autocomplete_selection
Moodle template for the currently selected items in an autocomplate form element.
Classes required for JS:
* none
Data attributes required for JS:
* none
Context variables required for this template:
* multiple True if this field allows multiple selections
* selectionId The dom id of the current selection list.
* items List of items with label and value fields.
* noSelectionString String to use when no items are selected
Example context (json):
{ "multiple": true, "selectionId": 1, "items": [
{ "label": "Item label with <strong>tags</strong>", "value": "5" },
{ "label": "Another item label with <strong>tags</strong>", "value": "4" }
], "noSelectionString": "No selection" }
}}
<div class="form-autocomplete-selection {{#multiple}}form-autocomplete-multiple{{/multiple}}" id="{{selectionId}}" role="list" aria-atomic="true" {{#multiple}}tabindex="0" aria-multiselectable="true"{{/multiple}}>
<span class="accesshide">{{#str}}selecteditems, form{{/str}}</span>
{{#items}}
<span role="listitem" data-value="{{value}}" aria-selected="true" class="tag tag-info">
{{#multiple}}<span aria-hidden="true">× </span>{{/multiple}}{{{label}}}
</span>
{{/items}}
{{^items}}
<span>{{noSelectionString}}</span>
{{/items}}
</div>
</div>

View File

@ -0,0 +1,16 @@
<div>
<textarea id="{{id}}" name="{{name}}[text]" class="form-control" rows="{{rows}}" cols="{{cols}}" spellcheck="true" {{#changelistener}} onblur="{{onblur}}"
onchange="{{onchange}}" {{/changelistener}}>{{text}}</textarea>
</div>
<div>
{{^onlyoneformat}}
<select name="{{name}}[format]" id="menu{{name}}format" class="custom-select">
{{#formats}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{text}}</option>
{{/formats}}
</select>
{{/onlyoneformat}}
{{#onlyoneformat}}
<input name="{{name}}[format]" id="menu{{name}}format" type="hidden" value="{{format}}"/>
{{/onlyoneformat}}
</div>

View File

@ -0,0 +1,3 @@
<input type="hidden" name="{{element.name}}"
value="{{element.value}}">
{{> core_form/element-checkbox-inline }}

View File

@ -0,0 +1,3 @@
<input type="hidden" name="{{element.name}}"
value="{{element.value}}">
{{> core_form/element-checkbox }}

View File

@ -0,0 +1,47 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9 form-inline">
<select class="custom-select {{#error}}form-control-danger{{/error}}" name="{{element.name}}"
id="{{element.id}}"
{{#element.multiple}}multiple{{/element.multiple}}
{{#element.frozen}}readonly disabled{{/element.frozen}}
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}}
{{#element.attributes}}
{{name}}={{#quote}}{{value}}{{/quote}} ddd
{{/element.attributes}}
>
{{#element.options}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{text}}</option>
{{/element.options}}
</select>
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,11 @@
<div class="form-group">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<button {{#element.frozen}}readonly{{/element.frozen}}
class="btn btn-secondary"
name="{{element.name}}"
id="{{element.id}}" >
{{{element.value}}}
</button>
</div>

View File

@ -0,0 +1,16 @@
<div class="form-group row">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9 form-inline">
<button {{#element.frozen}}readonly{{/element.frozen}}
class="btn btn-secondary m-l-0"
name="{{element.name}}"
id="{{element.id}}"
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}} >
{{{element.value}}}
</button>
</div>
</div>

View File

@ -0,0 +1,32 @@
<label class="form-check-inline {{#error}}has-danger{{/error}}">
<input type="checkbox" name="{{element.name}}"
id="{{element.id}}" value="{{element.value}}" size="{{element.size}}"
{{#element.frozen}}readonly disabled{{/element.frozen}}
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}} >
{{{label}}} {{{helpbutton}}}
</label>
<span class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</span>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,36 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<div class="col-md-9 push-md-3 checkbox">
<label>
<input type="checkbox" name="{{element.name}}"
id="{{element.id}}" value="{{element.value}}" size="{{element.size}}"
{{#element.frozen}}readonly disabled{{/element.frozen}}
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}} >
{{{label}}} {{{helpbutton}}}
</label>
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,10 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9 form-inline fdate_selector">
{{#element.elements}}
{{{.}}}
{{/element.elements}}
</div>
</div>

View File

@ -0,0 +1,13 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9 form-inline fdate_time_selector">
{{#element.elements}}
{{{.}}}
{{/element.elements}}
</div>
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>

View File

@ -0,0 +1 @@
{{> core_form/element-group }}

View File

@ -0,0 +1,33 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
{{{element.html}}}
<div class="form-control-feedback" id="id_error_{{element.name}}_5btext_5d" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,33 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
{{{element.html}}}
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,33 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
{{{element.html}}}
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,33 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
{{{element}}}
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,10 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9 form-inline">
{{#element.elements}}
{{{.}}}
{{/element.elements}}
</div>
</div>

View File

@ -0,0 +1 @@
{{> core_form/element-group }}

View File

@ -0,0 +1 @@
{{> core_form/element-select }}

View File

@ -0,0 +1,49 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
<input type="password"
{{#element.frozen}}readonly{{/element.frozen}}
class="form-control {{#error}}form-control-danger{{/error}}"
name="{{element.name}}"
id="{{element.id}}"
value="{{element.value}}"
size="{{element.size}}"
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}} >
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['core/yui'], function(Y) {
Y.use('moodle-form-passwordunmask', function() {
M.form.passwordunmask({ formid: {{#quote}}{{element.id}}{{/quote}},
checkboxlabel: '{{#str}}unmaskpassword, form{{/str}}',
checkboxname: {{#quote}}{{element.name}}{{/quote}} });
});
});
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1 @@
{{> core_form/element-selectgroups-inline }}

View File

@ -0,0 +1 @@
{{> core_form/element-selectgroups }}

View File

@ -0,0 +1,33 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
{{{element.html}}}
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,44 @@
<div class="form-group {{#error}}has-danger{{/error}}">
<label for="{{element.id}}" class="{{#element.hideLabel}}sr-only{{/element.hideLabel}}">
{{{label}}} {{{helpbutton}}}
</label>
<select class="custom-select {{#error}}form-control-danger{{/error}}" name="{{element.name}}"
id="{{element.id}}"
{{#element.multiple}}multiple{{/element.multiple}}
{{#element.frozen}}readonly disabled{{/element.frozen}}
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}}
{{#element.attributes}}
{{name}}={{#quote}}{{value}}{{/quote}}
{{/element.attributes}}>
{{#element.options}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{text}}</option>
{{/element.options}}
</select>
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,47 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
<select class="custom-select {{#error}}form-control-danger{{/error}}" name="{{element.name}}"
id="{{element.id}}"
{{#element.multiple}}multiple{{/element.multiple}}
{{#element.frozen}}readonly disabled{{/element.frozen}}
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}}
{{#element.attributes}}
{{name}}={{#quote}}{{value}}{{/quote}} ddd
{{/element.attributes}}
>
{{#element.options}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{text}}</option>
{{/element.options}}
</select>
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,44 @@
<div class="form-group {{#error}}has-danger{{/error}}">
<label for="{{element.id}}" class="{{#element.hideLabel}}sr-only{{/element.hideLabel}}">
{{{label}}} {{{helpbutton}}}
</label>
<select class="form-control {{#error}}form-control-danger{{/error}}" name="{{element.name}}"
id="{{element.id}}"
{{#element.multiple}}multiple{{/element.multiple}}
{{#element.frozen}}readonly disabled{{/element.frozen}}
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}}
{{#element.attributes}}
{{name}}={{#quote}}{{value}}{{/quote}}
{{/element.attributes}}>
{{#element.options}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{{text}}}</option>
{{/element.options}}
</select>
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,51 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
<select class="form-control {{#error}}form-control-danger{{/error}}" name="{{element.name}}"
id="{{element.id}}"
{{#element.multiple}}multiple{{/element.multiple}}
{{#element.frozen}}readonly disabled{{/element.frozen}}
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}}
{{#element.attributes}}
{{name}}={{#quote}}{{value}}{{/quote}}
{{/element.attributes}}
>
{{#element.optiongroups}}
<optgroup label="{{text}}">
{{#options}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{{text}}}</option>
{{/options}}
{{/element.optiongroups}}
</optgroup>
</select>
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1 @@
{{> core_form/element-select-inline }}

View File

@ -0,0 +1 @@
{{> core_form/element-select }}

View File

@ -0,0 +1,33 @@
<div class="form-group row fitem {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
{{{element.html}}}
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,10 @@
<div class="form-group">
<label class="col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<input type="submit" {{#element.frozen}}readonly{{/element.frozen}}
class="btn btn-primary"
name="{{element.name}}"
id="{{element.id}}"
value="{{element.value}}" >
</div>

View File

@ -0,0 +1,15 @@
<div class="form-group row">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9 form-inline">
<input type="submit" {{#element.frozen}}readonly{{/element.frozen}}
class="btn {{^iscancel}}btn-primary{{/iscancel}}{{#iscancel}}btn-secondary{{/iscancel}} m-l-0"
name="{{element.name}}"
id="{{element.id}}"
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}}
value="{{element.value}}">
</div>
</div>

View File

@ -0,0 +1,40 @@
<div class="form-group {{#error}}has-danger{{/error}}">
<label class="{{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<input type="text"
{{#element.frozen}}readonly{{/element.frozen}}
class="form-control {{#error}}form-control-danger{{/error}}"
name="{{element.name}}"
id="{{element.id}}"
value="{{element.value}}"
size="{{element.size}}"
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}} >
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,42 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
<input type="text"
{{#element.frozen}}readonly{{/element.frozen}}
class="form-control {{#error}}form-control-danger{{/error}}"
name="{{element.name}}"
id="{{element.id}}"
value="{{element.value}}"
size="{{element.size}}"
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}} >
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,33 @@
<div class="form-group row fitem {{#error}}has-danger{{/error}}" id="fitem_{{element.id}}">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
<textarea name="{{element.name}}" id="{{element.id}}">{{element.value}}</textarea>
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,43 @@
<div class="form-group row {{#error}}has-danger{{/error}}">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
<input type="url"
{{#element.frozen}}readonly{{/element.frozen}}
class="form-control {{#error}}form-control-danger{{/error}}"
name="{{element.name}}"
id="{{element.id}}"
value="{{element.value}}"
size="{{element.size}}"
{{#error}}
autofocus aria-describedby="id_error_{{element.name}}"
{{/error}} >
{{{element.filepickerhtml}}}
<div class="form-control-feedback" id="id_error_{{element.name}}" {{^error}} style="display: none;"{{/error}}>
{{{error}}}
</div>
</div>
</div>
{{#js}}
require(['jquery', 'core/event'], function($, Event) {
var element = document.getElementById('{{element.id}}');
$(element).on(Event.Events.FORM_FIELD_VALIDATION, function(event, msg) {
event.preventDefault();
var parent = $(element).closest('.form-group');
var feedback = parent.find('.form-control-feedback');
if (msg !== '') {
parent.addClass('has-danger');
$(element).addClass('form-control-danger');
$(element).attr('aria-describedby', $(element).attr('id') + '-feedback');
feedback.html(msg);
feedback.show();
} else {
parent.removeClass('has-danger');
$(element).removeClass('form-control-danger');
$(element).attr('aria-describedby', '');
feedback.hide();
}
});
});
{{/js}}

View File

@ -0,0 +1,10 @@
<div class="form-group row fitem has-danger">
<label class="col-md-3 col-form-label {{#element.hideLabel}}sr-only{{/element.hideLabel}}" for="{{element.id}}">
{{{label}}} {{{helpbutton}}}
</label>
<div class="col-md-9">
<div class="form-control-feedback" id="id_error_{{element.name}}">
{{{element.html}}}
</div>
</div>
</div>