Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/**
2
 * Show/hide admin settings based on other settings selected
3
 *
4
 * @copyright 2018 Davo Smith, Synergy Learning
5
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6
 */
7
define(['jquery'], function($) {
8
    var dependencies;
9
 
10
    // -------------------------------------------------
11
    // Support functions, used by dependency functions.
12
    // -------------------------------------------------
13
 
14
    /**
15
     * Check to see if the given element is the hidden element that makes sure checkbox
16
     * elements always submit a value.
17
     * @param {jQuery} $el
18
     * @returns {boolean}
19
     */
20
    function isCheckboxHiddenElement($el) {
21
        return ($el.is('input[type=hidden]') && $el.siblings('input[type=checkbox][name="' + $el.attr('name') + '"]').length);
22
    }
23
 
24
    /**
25
     * Check to see if this is a radio button with the wrong value (i.e. a radio button from
26
     * the group we are interested in, but not the specific one we wanted).
27
     * @param {jQuery} $el
28
     * @param {string} value
29
     * @returns {boolean}
30
     */
31
    function isWrongRadioButton($el, value) {
32
        return ($el.is('input[type=radio]') && $el.attr('value') !== value);
33
    }
34
 
35
    /**
36
     * Is this element relevant when we're looking for checked / not checked status?
37
     * @param {jQuery} $el
38
     * @param {string} value
39
     * @returns {boolean}
40
     */
41
    function isCheckedRelevant($el, value) {
42
        return (!isCheckboxHiddenElement($el) && !isWrongRadioButton($el, value));
43
    }
44
 
45
    /**
46
     * Is this an unchecked radio button? (If it is, we want to skip it, as
47
     * we're only interested in the value of the radio button that is checked)
48
     * @param {jQuery} $el
49
     * @returns {boolean}
50
     */
51
    function isUncheckedRadioButton($el) {
52
        return ($el.is('input[type=radio]') && !$el.prop('checked'));
53
    }
54
 
55
    /**
56
     * Is this an unchecked checkbox?
57
     * @param {jQuery} $el
58
     * @returns {boolean}
59
     */
60
    function isUncheckedCheckbox($el) {
61
        return ($el.is('input[type=checkbox]') && !$el.prop('checked'));
62
    }
63
 
64
    /**
65
     * Is this a multi-select select element?
66
     * @param {jQuery} $el
67
     * @returns {boolean}
68
     */
69
    function isMultiSelect($el) {
70
        return ($el.is('select') && $el.prop('multiple'));
71
    }
72
 
73
    /**
74
     * Does the multi-select exactly match the list of values provided?
75
     * @param {jQuery} $el
76
     * @param {array} values
77
     * @returns {boolean}
78
     */
79
    function multiSelectMatches($el, values) {
80
        var selected = $el.val() || [];
81
        if (!values.length) {
82
            // No values - nothing to match against.
83
            return false;
84
        }
85
        if (selected.length !== values.length) {
86
            // Different number of expected and actual values - cannot possibly be a match.
87
            return false;
88
        }
89
        for (var i in selected) {
90
            if (selected.hasOwnProperty(i)) {
91
                if (values.indexOf(selected[i]) === -1) {
92
                    return false; // Found a non-matching value - give up immediately.
93
                }
94
            }
95
        }
96
        // Didn't find a non-matching value, so we have a match.
97
        return true;
98
    }
99
 
100
    // -------------------------------
101
    // Specific dependency functions.
102
    // -------------------------------
103
 
104
    var depFns = {
105
        notchecked: function($dependon, value) {
106
            var hide = false;
107
            value = String(value);
108
            $dependon.each(function(idx, el) {
109
                var $el = $(el);
110
                if (isCheckedRelevant($el, value)) {
111
                    hide = hide || !$el.prop('checked');
112
                }
113
            });
114
            return hide;
115
        },
116
 
117
        checked: function($dependon, value) {
118
            var hide = false;
119
            value = String(value);
120
            $dependon.each(function(idx, el) {
121
                var $el = $(el);
122
                if (isCheckedRelevant($el, value)) {
123
                    hide = hide || $el.prop('checked');
124
                }
125
            });
126
            return hide;
127
        },
128
 
129
        noitemselected: function($dependon) {
130
            var hide = false;
131
            $dependon.each(function(idx, el) {
132
                var $el = $(el);
133
                hide = hide || ($el.prop('selectedIndex') === -1);
134
            });
135
            return hide;
136
        },
137
 
138
        eq: function($dependon, value) {
139
            var hide = false;
140
            var hiddenVal = false;
141
            value = String(value);
142
            $dependon.each(function(idx, el) {
143
                var $el = $(el);
144
                if (isUncheckedRadioButton($el)) {
145
                    // For radio buttons, we're only interested in the one that is checked.
146
                    return;
147
                }
148
                if (isCheckboxHiddenElement($el)) {
149
                    // This is the hidden input that is part of the checkbox setting.
150
                    // We will use this value, if the associated checkbox is unchecked.
151
                    hiddenVal = ($el.val() === value);
152
                    return;
153
                }
154
                if (isUncheckedCheckbox($el)) {
155
                    // Checkbox is not checked - hide depends on the 'unchecked' value stored in
156
                    // the associated hidden element, which we have already found, above.
157
                    hide = hide || hiddenVal;
158
                    return;
159
                }
160
                if (isMultiSelect($el)) {
161
                    // Expect a list of values to match, separated by '|' - all of them must
162
                    // match the values selected.
163
                    var values = value.split('|');
164
                    hide = multiSelectMatches($el, values);
165
                    return;
166
                }
167
                // All other element types - just compare the value directly.
168
                hide = hide || ($el.val() === value);
169
            });
170
            return hide;
171
        },
172
 
173
        'in': function($dependon, value) {
174
            var hide = false;
175
            var hiddenVal = false;
176
            var values = value.split('|');
177
            $dependon.each(function(idx, el) {
178
                var $el = $(el);
179
                if (isUncheckedRadioButton($el)) {
180
                    // For radio buttons, we're only interested in the one that is checked.
181
                    return;
182
                }
183
                if (isCheckboxHiddenElement($el)) {
184
                    // This is the hidden input that is part of the checkbox setting.
185
                    // We will use this value, if the associated checkbox is unchecked.
186
                    hiddenVal = (values.indexOf($el.val()) > -1);
187
                    return;
188
                }
189
                if (isUncheckedCheckbox($el)) {
190
                    // Checkbox is not checked - hide depends on the 'unchecked' value stored in
191
                    // the associated hidden element, which we have already found, above.
192
                    hide = hide || hiddenVal;
193
                    return;
194
                }
195
                if (isMultiSelect($el)) {
196
                    // For multiselect, we check to see if the list of values provided matches the list selected.
197
                    hide = multiSelectMatches($el, values);
198
                    return;
199
                }
200
                // All other element types - check to see if the value is in the list.
201
                hide = hide || (values.indexOf($el.val()) > -1);
202
            });
203
            return hide;
204
        },
205
 
206
        defaultCondition: function($dependon, value) { // Not equal.
207
            var hide = false;
208
            var hiddenVal = false;
209
            value = String(value);
210
            $dependon.each(function(idx, el) {
211
                var $el = $(el);
212
                if (isUncheckedRadioButton($el)) {
213
                    // For radio buttons, we're only interested in the one that is checked.
214
                    return;
215
                }
216
                if (isCheckboxHiddenElement($el)) {
217
                    // This is the hidden input that is part of the checkbox setting.
218
                    // We will use this value, if the associated checkbox is unchecked.
219
                    hiddenVal = ($el.val() !== value);
220
                    return;
221
                }
222
                if (isUncheckedCheckbox($el)) {
223
                    // Checkbox is not checked - hide depends on the 'unchecked' value stored in
224
                    // the associated hidden element, which we have already found, above.
225
                    hide = hide || hiddenVal;
226
                    return;
227
                }
228
                if (isMultiSelect($el)) {
229
                    // Expect a list of values to match, separated by '|' - all of them must
230
                    // match the values selected to *not* hide the element.
231
                    var values = value.split('|');
232
                    hide = !multiSelectMatches($el, values);
233
                    return;
234
                }
235
                // All other element types - just compare the value directly.
236
                hide = hide || ($el.val() !== value);
237
            });
238
            return hide;
239
        }
240
    };
241
 
242
    /**
243
     * Find the element with the given name
244
     * @param {String} name
245
     * @returns {*|jQuery|HTMLElement}
246
     */
247
    function getElementsByName(name) {
248
        // For the array elements, we use [name^="something["] to find the elements that their name begins with 'something['/
249
        // This is to find both name = 'something[]' and name='something[index]'.
250
        return $('[name="' + name + '"],[name^="' + name + '["]');
251
    }
252
 
253
    /**
254
     * Check to see whether a particular condition is met
255
     * @param {*|jQuery|HTMLElement} $dependon
256
     * @param {String} condition
257
     * @param {mixed} value
258
     * @returns {Boolean}
259
     */
260
    function checkDependency($dependon, condition, value) {
261
        if (typeof depFns[condition] === "function") {
262
            return depFns[condition]($dependon, value);
263
        }
264
        return depFns.defaultCondition($dependon, value);
265
    }
266
 
267
    /**
268
     * Show / hide the elements that depend on some elements.
269
     */
270
    function updateDependencies() {
271
        // Process all dependency conditions.
272
        var toHide = {};
273
        $.each(dependencies, function(dependonname) {
274
            var dependon = getElementsByName(dependonname);
275
            $.each(dependencies[dependonname], function(condition, values) {
276
                $.each(values, function(value, elements) {
277
                    var hide = checkDependency(dependon, condition, value);
278
                    $.each(elements, function(idx, elToHide) {
279
                        if (toHide.hasOwnProperty(elToHide)) {
280
                            toHide[elToHide] = toHide[elToHide] || hide;
281
                        } else {
282
                            toHide[elToHide] = hide;
283
                        }
284
                    });
285
                });
286
            });
287
        });
288
 
289
        // Update the hidden status of all relevant elements.
290
        $.each(toHide, function(elToHide, hide) {
291
            getElementsByName(elToHide).each(function(idx, el) {
292
                var $parent = $(el).closest('.form-item');
293
                if ($parent.length) {
294
                    if (hide) {
295
                        $parent.hide();
296
                    } else {
297
                        $parent.show();
298
                    }
299
                }
300
            });
301
        });
302
    }
303
 
304
    /**
305
     * Initialise the event handlers.
306
     */
307
    function initHandlers() {
308
        $.each(dependencies, function(depname) {
309
            var $el = getElementsByName(depname);
310
            if ($el.length) {
311
                $el.on('change', updateDependencies);
312
            }
313
        });
314
        updateDependencies();
315
    }
316
 
317
    /**
318
     * Hide the 'this setting may be hidden' messages.
319
     */
320
    function hideDependencyInfo() {
321
        $('.form-dependenton').hide();
322
    }
323
 
324
    return {
325
        init: function(opts) {
326
            dependencies = opts.dependencies;
327
            initHandlers();
328
            hideDependencyInfo();
329
        }
330
    };
331
});