MDL-67650 admin: Consistently show forced config settings
authorBrendan Heywood <brendan@catalyst-au.net>
Tue, 18 Feb 2020 12:42:58 +0000 (23:42 +1100)
committerBrendan Heywood <brendan@catalyst-au.net>
Thu, 22 Oct 2020 02:16:51 +0000 (13:16 +1100)
17 files changed:
admin/classes/local/settings/filesize.php
admin/templates/setting_configcheckbox.mustache
admin/templates/setting_configcolourpicker.mustache
admin/templates/setting_configdirectory.mustache
admin/templates/setting_configduration.mustache
admin/templates/setting_configexecutable.mustache
admin/templates/setting_configfile.mustache
admin/templates/setting_configfilesize.mustache
admin/templates/setting_configmultiselect.mustache
admin/templates/setting_configmultiselect_optgroup.mustache
admin/templates/setting_configpasswordunmask.mustache
admin/templates/setting_configselect.mustache
admin/templates/setting_configselect_optgroup.mustache
admin/templates/setting_configtext.mustache
admin/templates/setting_configtextarea.mustache
admin/templates/setting_configtime.mustache
lib/adminlib.php

index e5a6edb..3352f1e 100644 (file)
@@ -178,6 +178,7 @@ class filesize extends \admin_setting {
             'id' => $this->get_id(),
             'name' => $this->get_full_name(),
             'value' => $data['v'],
+            'readonly' => $this->is_readonly(),
             'options' => array_map(function($unit, $title) use ($data, $defaultunit) {
                 return [
                     'value' => $unit,
index f41e5a2..48e0471 100644 (file)
@@ -25,6 +25,7 @@
     * value - yes value
     * id - element id
     * checked - boole
+    * readonly - bool
 
     Example context (json):
     {
         "no": "False",
         "value": "True",
         "id": "test0",
-        "checked": "checked"
+        "checked": "checked",
+        "readonly": false
     }
 }}
 <div class="form-checkbox defaultsnext">
     <input type="hidden" name="{{name}}" value="{{no}}">
-    <input type="checkbox" name="{{name}}" value="{{value}}" id="{{id}}" {{#checked}}checked{{/checked}}>
+    <input {{#readonly}}disabled{{/readonly}} type="checkbox" name="{{name}}" value="{{value}}" id="{{id}}" {{#checked}}checked{{/checked}}>
 </div>
index 3de5aac..50b7da1 100644 (file)
@@ -25,6 +25,7 @@
     * id - element id
     * value - element value
     * haspreviewconfig - show preview of selected color
+    * readonly - bool
 
     Example context (json):
     {
@@ -32,6 +33,7 @@
         "name": "name0",
         "id": "id0",
         "value": "#555655",
+        "readonly": false,
         "haspreviewconfig": false
     }
 }}
@@ -44,7 +46,7 @@
             {{>core/pix_icon}}
         {{/icon}}
     </div>
-    <input type="text" name="{{name}}" id="{{id}}" value="{{value}}" size="12" class="form-control text-ltr">
+    <input type="text" name="{{name}}" id="{{id}}" value="{{value}}" size="12" class="form-control text-ltr" {{#readonly}}disabled{{/readonly}}>
     {{#haspreviewconfig}}
         <input type="button" id="{{id}}_preview" value={{#quote}}{{#str}}preview{{/str}}{{/quote}} class="admin_colourpicker_preview">
     {{/haspreviewconfig}}
index 1804787..cfe8a7d 100644 (file)
@@ -33,7 +33,7 @@
         "name": "test",
         "value": "/my-super-secret-path/",
         "id": "test0",
-        "readonly": true,
+        "readonly": false,
         "showvalidity": true,
         "valid": false
     }
index d20dabc..1a880c1 100644 (file)
@@ -23,6 +23,7 @@
     * name - form element name
     * options - list of options for units containing name, value, selected
     * value - yes
+    * readonly - bool
     * id - element id
 
     Example context (json):
@@ -30,6 +31,7 @@
         "name": "test",
         "value": "5",
         "id": "test0",
+        "readonly": false,
         "options": [ { "name": "Minutes", "value": "mins", "selected": true } ]
     }
 }}
@@ -38,9 +40,9 @@
 }}
 <div class="form-duration defaultsnext">
     <div class="form-inline">
-        <input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="form-control text-ltr">
+        <input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="form-control text-ltr" {{#readonly}}disabled{{/readonly}}>
         <label class="sr-only" for="{{id}}u">{{#str}}durationunits, admin{{/str}}</label>
-        <select id="{{id}}u" name="{{name}}[u]" class="form-control custom-select">
+        <select id="{{id}}u" name="{{name}}[u]" class="form-control custom-select" {{#readonly}}disabled{{/readonly}}>
             {{#options}}
                 <option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
             {{/options}}
index 72187f2..773b07d 100644 (file)
@@ -33,7 +33,7 @@
         "name": "test",
         "value": "/usr/bin/cowsay",
         "id": "test0",
-        "readonly": true,
+        "readonly": false,
         "showvalidity": true,
         "valid": false
     }
index 1f0b5d5..15a45ce 100644 (file)
@@ -26,6 +26,7 @@
     * readonly - Make the field readonly
     * value - value
     * showvalidity - Show a green check if the path is readable
+    * readonly - bool
     * valid - True if the path is readable
 
     Example context (json):
@@ -33,8 +34,9 @@
         "name": "test",
         "value": "/my-super-secret-path/file",
         "id": "test0",
-        "readonly": true,
+        "readonly": false,
         "showvalidity": true,
+        "readonly": false,
         "valid": false
     }
 }}
index 4716c6e..355cc6d 100644 (file)
     * options - list of options for units containing name, value, selected
     * value - yes
     * id - element id
+    * readonly - bool
 
     Example context (json):
     {
         "name": "test",
         "value": "5",
         "id": "test0",
+        "readonly": false,
         "options": [ { "name": "KB", "value": "1024", "selected": true } ]
     }
 }}
@@ -38,9 +40,9 @@
 }}
 <div class="form-filesize defaultsnext">
     <div class="form-inline">
-        <input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="form-control text-ltr">
+        <input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="form-control text-ltr" {{#readonly}}disabled{{/readonly}}>
         <label class="sr-only" for="{{id}}u">{{#str}}filesizeunits, admin{{/str}}</label>
-        <select id="{{id}}u" name="{{name}}[u]" class="form-control custom-select">
+        <select id="{{id}}u" name="{{name}}[u]" class="form-control custom-select" {{#readonly}}disabled{{/readonly}}>
             {{#options}}
                 <option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
             {{/options}}
index 49eb55c..c19b1fd 100644 (file)
     * id - element id
     * size - element size
     * options - list of options containing name, value, selected
+    * readonly - bool
 
     Example context (json):
     {
         "name": "test",
         "id": "test0",
+        "readonly": false,
         "size": "3",
         "options": [ { "name": "Option 1", "value": "V", "selected": true },
                      { "name": "Option 2", "value": "V", "selected": true } ]
@@ -39,7 +41,7 @@
 }}
 <div class="form-select">
     <input type="hidden" name="{{name}}[xxxxx]" value="1">
-    <select id="{{id}}" name="{{name}}[]" size="{{size}}" class="form-control" multiple>
+    <select {{#readonly}}disabled{{/readonly}} id="{{id}}" name="{{name}}[]" size="{{size}}" class="form-control" multiple>
         {{#options}}
             <option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
         {{/options}}
index 20d66e1..a1cbc9d 100644 (file)
     * size - element size
     * options - list of options not grouped
     * optgroups - list of options grouped containing the group label and for each option: name, value, selected
+    * readonly - bool
 
     Example context (json):
     {
         "name": "test",
         "id": "test0",
+        "readonly": false,
         "size": "3",
         "options": [
             { "name": "Option 1", "value": "V", "selected": false },
@@ -58,7 +60,7 @@
 }}
 <div class="form-select">
     <input type="hidden" name="{{name}}[xxxxx]" value="1">
-    <select id="{{id}}" name="{{name}}[]" size="{{size}}" class="form-control" multiple>
+    <select {{#readonly}}disabled{{/readonly}} id="{{id}}" name="{{name}}[]" size="{{size}}" class="form-control" multiple>
     {{#options}}
         <option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
     {{/options}}
index 7092e82..84a27a6 100644 (file)
@@ -24,7 +24,7 @@
     * size - form element size
     * value - form element value
     * id - element id
-    * forced - has value been defined in config.php
+    * readonly - has value been defined in config.php
 
     Example context (json):
     {
         "id": "test0",
         "size": "8",
         "value": "secret",
-        "forced": false
+        "readonly": false
     }
 }}
-{{#forced}}
+{{#readonly}}
     <div class="form-password">
         <input type="text"
                name = "{{ name }}"
@@ -46,8 +46,8 @@
                disabled
         >
     </div>
-{{/forced}}
-{{^forced}}
+{{/readonly}}
+{{^readonly}}
 <div class="form-password">
     <span data-passwordunmask="wrapper" data-passwordunmaskid="{{ id }}">
         <span data-passwordunmask="editor">
@@ -76,4 +76,4 @@ require(['core_form/passwordunmask'], function(PasswordUnmask) {
     new PasswordUnmask("{{ id }}");
 });
 {{/js}}
-{{/forced}}
+{{/readonly}}
index 9b6c6e1..eb18b4b 100644 (file)
     * name - form element name
     * id - element id
     * options - list of options containing name, value, selected
+    * readonly - bool
 
     Example context (json):
     {
         "name": "test",
         "id": "test0",
+        "readonly": false,
         "options": [
             { "name": "Option 1", "value": "V", "selected": true },
             { "name": "Option 2", "value": "V", "selected": true }
@@ -38,7 +40,7 @@
     Setting configselect.
 }}
 <div class="form-select defaultsnext">
-    <select id="{{id}}" name="{{name}}" class="custom-select">
+    <select {{#readonly}}disabled{{/readonly}} id="{{id}}" name="{{name}}" class="custom-select">
         {{#options}}
             <option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
         {{/options}}
index 95f818b..862ac61 100644 (file)
@@ -22,6 +22,7 @@
     Context variables required for this template:
     * name - form element name
     * id - element id
+    * readonly - bool
     * options - list of options (not grouped)
     * optgroups - list of options grouped containing the group label and for each option: name, value, selected
 
@@ -29,6 +30,7 @@
     {
         "name": "test",
         "id": "test0",
+        "readonly": false,
         "options": [
             { "name": "Option 1", "value": "V", "selected": false },
             { "name": "Option 2", "value": "V", "selected": false }
@@ -55,7 +57,7 @@
     Setting configselect with optgroup support.
 }}
 <div class="form-select defaultsnext">
-    <select id="{{id}}" name="{{name}}" class="custom-select">
+    <select {{#readonly}}disabled{{/readonly}} id="{{id}}" name="{{name}}" class="custom-select">
         {{#options}}
             <option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
         {{/options}}
index a31f73a..1238c8e 100644 (file)
@@ -26,6 +26,7 @@
     * size - element size
     * forceltr - always display as ltr
     * attributes - list of additional attributes containing name, value
+    * readonly - bool
 
     Example context (json):
     {
@@ -34,6 +35,7 @@
         "value": "A tall, dark stranger will have more fun than you.",
         "size": "21",
         "forceltr": false,
+        "readonly": false,
         "attributes": [ { "name": "readonly", "value": "readonly" } ]
     }
 }}
@@ -41,5 +43,5 @@
     Setting configtext.
 }}
 <div class="form-text defaultsnext">
-    <input type="text" name="{{name}}" value="{{value}}" size="{{size}}" id="{{id}}" class="form-control {{#forceltr}}text-ltr{{/forceltr}}">
+    <input type="text" name="{{name}}" value="{{value}}" size="{{size}}" id="{{id}}" class="form-control {{#forceltr}}text-ltr{{/forceltr}}" {{#readonly}}disabled{{/readonly}}>
 </div>
index 002b0cd..c877d94 100644 (file)
@@ -33,6 +33,7 @@
         "cols": "30",
         "rows": "3",
         "value": "Excellent day for putting Slinkies on an escalator.",
+        "readonly": false,
         "id": "test0"
     }
 }}
@@ -40,5 +41,5 @@
     Setting configtextarea.
 }}
 <div class="form-textarea">
-    <textarea rows="{{rows}}" cols="{{cols}}" id="{{id}}" name="{{name}}" spellcheck="true" class="form-control {{#forceltr}}text-ltr{{/forceltr}}">{{value}}</textarea>
+    <textarea {{#readonly}}disabled{{/readonly}} rows="{{rows}}" cols="{{cols}}" id="{{id}}" name="{{name}}" spellcheck="true" class="form-control {{#forceltr}}text-ltr{{/forceltr}}">{{value}}</textarea>
 </div>
index 90d37b3..af4435a 100644 (file)
     * id - element id
     * hours - list of valid hour options containing name, value, selected
     * minutes - list of valid minute options containing name, value, selected
+    * readonly - bool
 
     Example context (json):
     {
         "name": "test",
         "id": "test0",
+        "readonly": false,
         "minutes": [
             { "name": "00", "value": "0", "selected": true },
             { "name": "01", "value": "1", "selected": false }
 <div class="form-time defaultsnext">
     <div class="form-inline text-ltr">
         <label class="sr-only" for="{{id}}h">{{#str}}hours{{/str}}</label>
-        <select id="{{id}}h" name="{{name}}[h]" class="custom-select">
+        <select id="{{id}}h" name="{{name}}[h]" class="custom-select" {{#readonly}}disabled{{/readonly}}>
             {{#hours}}
                 <option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
             {{/hours}}
         </select>:
         <label class="sr-only" for="{{id}}m">{{#str}}minutes{{/str}}</label>
-        <select id="{{id}}m" name="{{name}}[m]" class="custom-select">
+        <select id="{{id}}m" name="{{name}}[m]" class="custom-select" {{#readonly}}disabled{{/readonly}}>
             {{#minutes}}
                 <option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
             {{/minutes}}
index 4d55c9f..1c4492f 100644 (file)
@@ -1761,6 +1761,27 @@ abstract class admin_setting {
         $this->set_flag_options($enabled, $default, 'required', new lang_string('required', 'core_admin'));
     }
 
+    /**
+     * Is this option forced in config.php?
+     *
+     * @return bool
+     */
+    public function is_readonly(): bool {
+        global $CFG;
+
+        if (empty($this->plugin)) {
+            if (array_key_exists($this->name, $CFG->config_php_settings)) {
+                return true;
+            }
+        } else {
+            if (array_key_exists($this->plugin, $CFG->forced_plugin_settings)
+                and array_key_exists($this->name, $CFG->forced_plugin_settings[$this->plugin])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Get the currently saved value for a setting flag
      *
@@ -2460,6 +2481,7 @@ class admin_setting_configtext extends admin_setting {
             'name' => $this->get_full_name(),
             'value' => $data,
             'forceltr' => $this->get_force_ltr(),
+            'readonly' => $this->is_readonly(),
         ];
         $element = $OUTPUT->render_from_template('core_admin/setting_configtext', $context);
 
@@ -2568,6 +2590,7 @@ class admin_setting_configtextarea extends admin_setting_configtext {
             'name' => $this->get_full_name(),
             'value' => $data,
             'forceltr' => $this->get_force_ltr(),
+            'readonly' => $this->is_readonly(),
         ];
         $element = $OUTPUT->render_from_template('core_admin/setting_configtextarea', $context);
 
@@ -2664,25 +2687,15 @@ class admin_setting_configpasswordunmask extends admin_setting_configtext {
      * @return  string              Rendered HTML
      */
     public function output_html($data, $query='') {
-        global $OUTPUT, $CFG;
-        $forced = false;
-        if (empty($this->plugin)) {
-            if (array_key_exists($this->name, $CFG->config_php_settings)) {
-                $forced = true;
-            }
-        } else {
-            if (array_key_exists($this->plugin, $CFG->forced_plugin_settings)
-                and array_key_exists($this->name, $CFG->forced_plugin_settings[$this->plugin])) {
-                $forced = true;
-            }
-        }
+        global $OUTPUT;
+
         $context = (object) [
             'id' => $this->get_id(),
             'name' => $this->get_full_name(),
             'size' => $this->size,
-            'value' => $forced ? null : $data,
+            'value' => $this->is_readonly() ? null : $data,
             'forceltr' => $this->get_force_ltr(),
-            'forced' => $forced
+            'readonly' => $this->is_readonly(),
         ];
         $element = $OUTPUT->render_from_template('core_admin/setting_configpasswordunmask', $context);
         return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', null, $query);
@@ -2787,7 +2800,7 @@ class admin_setting_configfile extends admin_setting_configtext {
             'value' => $data,
             'showvalidity' => !empty($data),
             'valid' => $data && file_exists($data),
-            'readonly' => !empty($CFG->preventexecpath),
+            'readonly' => !empty($CFG->preventexecpath) || $this->is_readonly(),
             'forceltr' => $this->get_force_ltr(),
         ];
 
@@ -2972,6 +2985,7 @@ class admin_setting_configcheckbox extends admin_setting {
             'no' => $this->no,
             'value' => $this->yes,
             'checked' => (string) $data === $this->yes,
+            'readonly' => $this->is_readonly(),
         ];
 
         $default = $this->get_defaultsetting();
@@ -3463,6 +3477,7 @@ class admin_setting_configselect extends admin_setting {
             ];
         }
         $context->options = $options;
+        $context->readonly = $this->is_readonly();
 
         $element = $OUTPUT->render_from_template($template, $context);
 
@@ -3620,6 +3635,7 @@ class admin_setting_configmultiselect extends admin_setting_configselect {
             ];
         }
         $context->options = $options;
+        $context->readonly = $this->is_readonly();
 
         if (is_null($default)) {
             $defaultinfo = NULL;
@@ -3710,6 +3726,7 @@ class admin_setting_configtime extends admin_setting {
         $context = (object) [
             'id' => $this->get_id(),
             'name' => $this->get_full_name(),
+            'readonly' => $this->is_readonly(),
             'hours' => array_map(function($i) use ($data) {
                 return [
                     'value' => $i,
@@ -3884,6 +3901,7 @@ class admin_setting_configduration extends admin_setting {
             'id' => $this->get_id(),
             'name' => $this->get_full_name(),
             'value' => $data['v'],
+            'readonly' => $this->is_readonly(),
             'options' => array_map(function($unit) use ($units, $data, $defaultunit) {
                 return [
                     'value' => $unit,
@@ -10506,7 +10524,8 @@ class admin_setting_configcolourpicker extends admin_setting {
             'value' => $data,
             'icon' => $icon->export_for_template($OUTPUT),
             'haspreviewconfig' => !empty($this->previewconfig),
-            'forceltr' => $this->get_force_ltr()
+            'forceltr' => $this->get_force_ltr(),
+            'readonly' => $this->is_readonly(),
         ];
 
         $element = $OUTPUT->render_from_template('core_admin/setting_configcolourpicker', $context);