3 * Provides a JavaScript API to broadcast text editor configuration changes.
5 * Filter implementations may listen to the drupalEditorFeatureAdded,
6 * drupalEditorFeatureRemoved, and drupalEditorFeatureRemoved events on document
7 * to automatically adjust their settings based on the editor configuration.
10 (function ($, _, Drupal, document) {
15 * Editor configuration namespace.
19 Drupal.editorConfiguration = {
22 * Must be called by a specific text editor's configuration whenever a
23 * feature is added by the user.
25 * Triggers the drupalEditorFeatureAdded event on the document, which
26 * receives a {@link Drupal.EditorFeature} object.
28 * @param {Drupal.EditorFeature} feature
29 * A text editor feature object.
31 * @fires event:drupalEditorFeatureAdded
33 addedFeature: function (feature) {
34 $(document).trigger('drupalEditorFeatureAdded', feature);
38 * Must be called by a specific text editor's configuration whenever a
39 * feature is removed by the user.
41 * Triggers the drupalEditorFeatureRemoved event on the document, which
42 * receives a {@link Drupal.EditorFeature} object.
44 * @param {Drupal.EditorFeature} feature
45 * A text editor feature object.
47 * @fires event:drupalEditorFeatureRemoved
49 removedFeature: function (feature) {
50 $(document).trigger('drupalEditorFeatureRemoved', feature);
54 * Must be called by a specific text editor's configuration whenever a
55 * feature is modified, i.e. has different rules.
57 * For example when the "Bold" button is configured to use the `<b>` tag
58 * instead of the `<strong>` tag.
60 * Triggers the drupalEditorFeatureModified event on the document, which
61 * receives a {@link Drupal.EditorFeature} object.
63 * @param {Drupal.EditorFeature} feature
64 * A text editor feature object.
66 * @fires event:drupalEditorFeatureModified
68 modifiedFeature: function (feature) {
69 $(document).trigger('drupalEditorFeatureModified', feature);
73 * May be called by a specific text editor's configuration whenever a
74 * feature is being added, to check whether it would require the filter
75 * settings to be updated.
77 * The canonical use case is when a text editor is being enabled:
79 * this would not cause the filter settings to be changed; rather, the
80 * default set of buttons (features) for the text editor should adjust
81 * itself to not cause filter setting changes.
83 * Note: for filters to integrate with this functionality, it is necessary
85 * `Drupal.filterSettingsForEditors[filterID].getRules()`.
87 * @param {Drupal.EditorFeature} feature
88 * A text editor feature object.
91 * Whether the given feature is allowed by the current filters.
93 featureIsAllowedByFilters: function (feature) {
96 * Generate the universe U of possible values that can result from the
97 * feature's rules' requirements.
99 * This generates an object of this form:
102 * 'touchedByAllowedPropertyRule': false,
104 * 'attributes:href': false,
105 * 'classes:external': false,
108 * 'touchedByAllowedPropertyRule': false,
112 * 'touchedByAllowedPropertyRule': false,
114 * 'attributes:src': false
118 * In this example, the given text editor feature resulted in the above
119 * universe, which shows that it must be allowed to generate the a,
120 * strong and img tags. For the a tag, it must be able to set the "href"
121 * attribute and the "external" class. For the strong tag, no further
122 * properties are required. For the img tag, the "src" attribute is
123 * required. The "tag" key is used to track whether that tag was
124 * explicitly allowed by one of the filter's rules. The
125 * "touchedByAllowedPropertyRule" key is used for state tracking that is
126 * essential for filterStatusAllowsFeature() to be able to reason: when
127 * all of a filter's rules have been applied, and none of the forbidden
128 * rules matched (which would have resulted in early termination) yet the
129 * universe has not been made empty (which would be the end result if
130 * everything in the universe were explicitly allowed), then this piece
131 * of state data enables us to determine whether a tag whose properties
132 * were not all explicitly allowed are in fact still allowed, because its
133 * tag was explicitly allowed and there were no filter rules applying
134 * "allowed tag property value" restrictions for this particular tag.
136 * @param {object} feature
137 * The feature in question.
140 * The universe generated.
142 * @see findPropertyValueOnTag()
143 * @see filterStatusAllowsFeature()
145 function generateUniverseFromFeatureRequirements(feature) {
146 var properties = ['attributes', 'styles', 'classes'];
149 for (var r = 0; r < feature.rules.length; r++) {
150 var featureRule = feature.rules[r];
152 // For each tag required by this feature rule, create a basic entry in
154 var requiredTags = featureRule.required.tags;
155 for (var t = 0; t < requiredTags.length; t++) {
156 universe[requiredTags[t]] = {
157 // Whether this tag was allowed or not.
159 // Whether any filter rule that applies to this tag had an allowed
160 // property rule. i.e. will become true if >=1 filter rule has >=1
161 // allowed property rule.
162 touchedByAllowedPropertyRule: false,
163 // Analogous, but for forbidden property rule.
164 touchedBytouchedByForbiddenPropertyRule: false
168 // If no required properties are defined for this rule, we can move on
169 // to the next feature.
170 if (emptyProperties(featureRule.required)) {
174 // Expand the existing universe, assume that each tags' property
175 // value is disallowed. If the filter rules allow everything in the
176 // feature's universe, then the feature is allowed.
177 for (var p = 0; p < properties.length; p++) {
178 var property = properties[p];
179 for (var pv = 0; pv < featureRule.required[property].length; pv++) {
180 var propertyValue = featureRule.required[property];
181 universe[requiredTags][property + ':' + propertyValue] = false;
190 * Provided a section of a feature or filter rule, checks if no property
191 * values are defined for all properties: attributes, classes and styles.
193 * @param {object} section
194 * The section to check.
197 * Returns true if the section has empty properties, false otherwise.
199 function emptyProperties(section) {
200 return section.attributes.length === 0 && section.classes.length === 0 && section.styles.length === 0;
204 * Calls findPropertyValueOnTag on the given tag for every property value
205 * that is listed in the "propertyValues" parameter. Supports the wildcard
208 * @param {object} universe
209 * The universe to check.
210 * @param {string} tag
211 * The tag to look for.
212 * @param {string} property
213 * The property to check.
214 * @param {Array} propertyValues
215 * Values of the property to check.
216 * @param {bool} allowing
217 * Whether to update the universe or not.
220 * Returns true if found, false otherwise.
222 function findPropertyValuesOnTag(universe, tag, property, propertyValues, allowing) {
223 // Detect the wildcard case.
225 return findPropertyValuesOnAllTags(universe, property, propertyValues, allowing);
228 var atLeastOneFound = false;
229 _.each(propertyValues, function (propertyValue) {
230 if (findPropertyValueOnTag(universe, tag, property, propertyValue, allowing)) {
231 atLeastOneFound = true;
234 return atLeastOneFound;
238 * Calls findPropertyValuesOnAllTags for all tags in the universe.
240 * @param {object} universe
241 * The universe to check.
242 * @param {string} property
243 * The property to check.
244 * @param {Array} propertyValues
245 * Values of the property to check.
246 * @param {bool} allowing
247 * Whether to update the universe or not.
250 * Returns true if found, false otherwise.
252 function findPropertyValuesOnAllTags(universe, property, propertyValues, allowing) {
253 var atLeastOneFound = false;
254 _.each(_.keys(universe), function (tag) {
255 if (findPropertyValuesOnTag(universe, tag, property, propertyValues, allowing)) {
256 atLeastOneFound = true;
259 return atLeastOneFound;
263 * Finds out if a specific property value (potentially containing
264 * wildcards) exists on the given tag. When the "allowing" parameter
265 * equals true, the universe will be updated if that specific property
266 * value exists. Returns true if found, false otherwise.
268 * @param {object} universe
269 * The universe to check.
270 * @param {string} tag
271 * The tag to look for.
272 * @param {string} property
273 * The property to check.
274 * @param {string} propertyValue
275 * The property value to check.
276 * @param {bool} allowing
277 * Whether to update the universe or not.
280 * Returns true if found, false otherwise.
282 function findPropertyValueOnTag(universe, tag, property, propertyValue, allowing) {
283 // If the tag does not exist in the universe, then it definitely can't
284 // have this specific property value.
285 if (!_.has(universe, tag)) {
289 var key = property + ':' + propertyValue;
291 // Track whether a tag was touched by a filter rule that allows specific
292 // property values on this particular tag.
293 // @see generateUniverseFromFeatureRequirements
295 universe[tag].touchedByAllowedPropertyRule = true;
298 // The simple case: no wildcard in property value.
299 if (_.indexOf(propertyValue, '*') === -1) {
300 if (_.has(universe, tag) && _.has(universe[tag], key)) {
302 universe[tag][key] = true;
308 // The complex case: wildcard in property value.
310 var atLeastOneFound = false;
311 var regex = key.replace(/\*/g, '[^ ]*');
312 _.each(_.keys(universe[tag]), function (key) {
313 if (key.match(regex)) {
314 atLeastOneFound = true;
316 universe[tag][key] = true;
320 return atLeastOneFound;
325 * Deletes a tag from the universe if the tag itself and each of its
326 * properties are marked as allowed.
328 * @param {object} universe
329 * The universe to delete from.
330 * @param {string} tag
334 * Whether something was deleted from the universe.
336 function deleteFromUniverseIfAllowed(universe, tag) {
337 // Detect the wildcard case.
339 return deleteAllTagsFromUniverseIfAllowed(universe);
341 if (_.has(universe, tag) && _.every(_.omit(universe[tag], 'touchedByAllowedPropertyRule'))) {
342 delete universe[tag];
349 * Calls deleteFromUniverseIfAllowed for all tags in the universe.
351 * @param {object} universe
352 * The universe to delete from.
355 * Whether something was deleted from the universe.
357 function deleteAllTagsFromUniverseIfAllowed(universe) {
358 var atLeastOneDeleted = false;
359 _.each(_.keys(universe), function (tag) {
360 if (deleteFromUniverseIfAllowed(universe, tag)) {
361 atLeastOneDeleted = true;
364 return atLeastOneDeleted;
368 * Checks if any filter rule forbids either a tag or a tag property value
369 * that exists in the universe.
371 * @param {object} universe
373 * @param {object} filterStatus
374 * Filter status to use for check.
377 * Whether any filter rule forbids something in the universe.
379 function anyForbiddenFilterRuleMatches(universe, filterStatus) {
380 var properties = ['attributes', 'styles', 'classes'];
382 // Check if a tag in the universe is forbidden.
383 var allRequiredTags = _.keys(universe);
385 for (var i = 0; i < filterStatus.rules.length; i++) {
386 filterRule = filterStatus.rules[i];
387 if (filterRule.allow === false) {
388 if (_.intersection(allRequiredTags, filterRule.tags).length > 0) {
394 // Check if a property value of a tag in the universe is forbidden.
395 // For all filter rules…
396 for (var n = 0; n < filterStatus.rules.length; n++) {
397 filterRule = filterStatus.rules[n];
398 // … if there are tags with restricted property values …
399 if (filterRule.restrictedTags.tags.length && !emptyProperties(filterRule.restrictedTags.forbidden)) {
400 // … for all those tags …
401 for (var j = 0; j < filterRule.restrictedTags.tags.length; j++) {
402 var tag = filterRule.restrictedTags.tags[j];
403 // … then iterate over all properties …
404 for (var k = 0; k < properties.length; k++) {
405 var property = properties[k];
406 // … and return true if just one of the forbidden property
407 // values for this tag and property is listed in the universe.
408 if (findPropertyValuesOnTag(universe, tag, property, filterRule.restrictedTags.forbidden[property], false)) {
420 * Applies every filter rule's explicit allowing of a tag or a tag
421 * property value to the universe. Whenever both the tag and all of its
422 * required property values are marked as explicitly allowed, they are
423 * deleted from the universe.
425 * @param {object} universe
426 * Universe to delete from.
427 * @param {object} filterStatus
428 * The filter status in question.
430 function markAllowedTagsAndPropertyValues(universe, filterStatus) {
431 var properties = ['attributes', 'styles', 'classes'];
433 // Check if a tag in the universe is allowed.
436 for (var l = 0; !_.isEmpty(universe) && l < filterStatus.rules.length; l++) {
437 filterRule = filterStatus.rules[l];
438 if (filterRule.allow === true) {
439 for (var m = 0; !_.isEmpty(universe) && m < filterRule.tags.length; m++) {
440 tag = filterRule.tags[m];
441 if (_.has(universe, tag)) {
442 universe[tag].tag = true;
443 deleteFromUniverseIfAllowed(universe, tag);
449 // Check if a property value of a tag in the universe is allowed.
450 // For all filter rules…
451 for (var i = 0; !_.isEmpty(universe) && i < filterStatus.rules.length; i++) {
452 filterRule = filterStatus.rules[i];
453 // … if there are tags with restricted property values …
454 if (filterRule.restrictedTags.tags.length && !emptyProperties(filterRule.restrictedTags.allowed)) {
455 // … for all those tags …
456 for (var j = 0; !_.isEmpty(universe) && j < filterRule.restrictedTags.tags.length; j++) {
457 tag = filterRule.restrictedTags.tags[j];
458 // … then iterate over all properties …
459 for (var k = 0; k < properties.length; k++) {
460 var property = properties[k];
461 // … and try to delete this tag from the universe if just one
462 // of the allowed property values for this tag and property is
463 // listed in the universe. (Because everything might be allowed
465 if (findPropertyValuesOnTag(universe, tag, property, filterRule.restrictedTags.allowed[property], true)) {
466 deleteFromUniverseIfAllowed(universe, tag);
475 * Checks whether the current status of a filter allows a specific feature
476 * by building the universe of potential values from the feature's
477 * requirements and then checking whether anything in the filter prevents
480 * @param {object} filterStatus
481 * The filter status in question.
482 * @param {object} feature
483 * The feature requested.
486 * Whether the current status of the filter allows specified feature.
488 * @see generateUniverseFromFeatureRequirements()
490 function filterStatusAllowsFeature(filterStatus, feature) {
491 // An inactive filter by definition allows the feature.
492 if (!filterStatus.active) {
496 // A feature that specifies no rules has no HTML requirements and is
497 // hence allowed by definition.
498 if (feature.rules.length === 0) {
502 // Analogously for a filter that specifies no rules.
503 if (filterStatus.rules.length === 0) {
507 // Generate the universe U of possible values that can result from the
508 // feature's rules' requirements.
509 var universe = generateUniverseFromFeatureRequirements(feature);
511 // If anything that is in the universe (and is thus required by the
512 // feature) is forbidden by any of the filter's rules, then this filter
513 // does not allow this feature.
514 if (anyForbiddenFilterRuleMatches(universe, filterStatus)) {
518 // Mark anything in the universe that is allowed by any of the filter's
519 // rules as allowed. If everything is explicitly allowed, then the
520 // universe will become empty.
521 markAllowedTagsAndPropertyValues(universe, filterStatus);
523 // If there was at least one filter rule allowing tags, then everything
524 // in the universe must be allowed for this feature to be allowed, and
525 // thus by now it must be empty. However, it is still possible that the
526 // filter allows the feature, due to no rules for allowing tag property
527 // values and/or rules for forbidding tag property values. For details:
528 // see the comments below.
529 // @see generateUniverseFromFeatureRequirements()
530 if (_.some(_.pluck(filterStatus.rules, 'allow'))) {
531 // If the universe is empty, then everything was explicitly allowed
532 // and our job is done: this filter allows this feature!
533 if (_.isEmpty(universe)) {
536 // Otherwise, it is still possible that this feature is allowed.
538 // Every tag must be explicitly allowed if there are filter rules
539 // doing tag whitelisting.
540 if (!_.every(_.pluck(universe, 'tag'))) {
543 // Every tag was explicitly allowed, but since the universe is not
544 // empty, one or more tag properties are disallowed. However, if
545 // only blacklisting of tag properties was applied to these tags,
546 // and no whitelisting was ever applied, then it's still fine:
547 // since none of the tag properties were blacklisted, we got to
548 // this point, and since no whitelisting was applied, it doesn't
549 // matter that the properties: this could never have happened
550 // anyway. It's only this late that we can know this for certain.
552 var tags = _.keys(universe);
553 // Figure out if there was any rule applying whitelisting tag
554 // restrictions to each of the remaining tags.
555 for (var i = 0; i < tags.length; i++) {
557 if (_.has(universe, tag)) {
558 if (universe[tag].touchedByAllowedPropertyRule === false) {
559 delete universe[tag];
563 return _.isEmpty(universe);
567 // Otherwise, if all filter rules were doing blacklisting, then the sole
568 // fact that we got to this point indicates that this filter allows for
569 // everything that is required for this feature.
575 // If any filter's current status forbids the editor feature, return
577 Drupal.filterConfiguration.update();
578 for (var filterID in Drupal.filterConfiguration.statuses) {
579 if (Drupal.filterConfiguration.statuses.hasOwnProperty(filterID)) {
580 var filterStatus = Drupal.filterConfiguration.statuses[filterID];
581 if (!(filterStatusAllowsFeature(filterStatus, feature))) {
592 * Constructor for an editor feature HTML rule.
594 * Intended to be used in combination with {@link Drupal.EditorFeature}.
596 * A text editor feature rule object describes both:
597 * - required HTML tags, attributes, styles and classes: without these, the
598 * text editor feature is unable to function. It's possible that a
599 * - allowed HTML tags, attributes, styles and classes: these are optional
600 * in the strictest sense, but it is possible that the feature generates
603 * The structure can be very clearly seen below: there's a "required" and an
604 * "allowed" key. For each of those, there are objects with the "tags",
605 * "attributes", "styles" and "classes" keys. For all these keys the values
606 * are initialized to the empty array. List each possible value as an array
607 * value. Besides the "required" and "allowed" keys, there's an optional
608 * "raw" key: it allows text editor implementations to optionally pass in
609 * their raw representation instead of the Drupal-defined representation for
614 * attributes: ['href', 'alt']
615 * styles: ['color', 'text-decoration']
616 * classes: ['external', 'internal']
620 * @see Drupal.EditorFeature
622 Drupal.EditorFeatureHTMLRule = function () {
629 * @prop {Array} attributes
630 * @prop {Array} styles
631 * @prop {Array} classes
633 this.required = {tags: [], attributes: [], styles: [], classes: []};
640 * @prop {Array} attributes
641 * @prop {Array} styles
642 * @prop {Array} classes
644 this.allowed = {tags: [], attributes: [], styles: [], classes: []};
654 * A text editor feature object. Initialized with the feature name.
656 * Contains a set of HTML rules ({@link Drupal.EditorFeatureHTMLRule} objects)
657 * that describe which HTML tags, attributes, styles and classes are required
658 * (i.e. essential for the feature to function at all) and which are allowed
659 * (i.e. the feature may generate this, but they're not essential).
661 * It is necessary to allow for multiple HTML rules per feature: with just
662 * one HTML rule per feature, there is not enough expressiveness to describe
663 * certain cases. For example: a "table" feature would probably require the
664 * `<table>` tag, and might allow e.g. the "summary" attribute on that tag.
665 * However, the table feature would also require the `<tr>` and `<td>` tags,
666 * but it doesn't make sense to allow for a "summary" attribute on these tags.
667 * Hence these would need to be split in two separate rules.
669 * HTML rules must be added with the `addHTMLRule()` method. A feature that
670 * has zero HTML rules does not create or modify HTML.
674 * @param {string} name
675 * The name of the feature.
677 * @see Drupal.EditorFeatureHTMLRule
679 Drupal.EditorFeature = function (name) {
685 * Adds a HTML rule to the list of HTML rules for this feature.
687 * @param {Drupal.EditorFeatureHTMLRule} rule
688 * A text editor feature HTML rule.
690 Drupal.EditorFeature.prototype.addHTMLRule = function (rule) {
691 this.rules.push(rule);
695 * Text filter status object. Initialized with the filter ID.
697 * Indicates whether the text filter is currently active (enabled) or not.
699 * Contains a set of HTML rules ({@link Drupal.FilterHTMLRule} objects) that
700 * describe which HTML tags are allowed or forbidden. They can also describe
701 * for a set of tags (or all tags) which attributes, styles and classes are
702 * allowed and which are forbidden.
704 * It is necessary to allow for multiple HTML rules per feature, for
705 * analogous reasons as {@link Drupal.EditorFeature}.
707 * HTML rules must be added with the `addHTMLRule()` method. A filter that has
708 * zero HTML rules does not disallow any HTML.
712 * @param {string} name
713 * The name of the feature.
715 * @see Drupal.FilterHTMLRule
717 Drupal.FilterStatus = function (name) {
733 * @type {Array.<Drupal.FilterHTMLRule>}
739 * Adds a HTML rule to the list of HTML rules for this filter.
741 * @param {Drupal.FilterHTMLRule} rule
742 * A text filter HTML rule.
744 Drupal.FilterStatus.prototype.addHTMLRule = function (rule) {
745 this.rules.push(rule);
749 * A text filter HTML rule object.
751 * Intended to be used in combination with {@link Drupal.FilterStatus}.
753 * A text filter rule object describes:
754 * 1. allowed or forbidden tags: (optional) whitelist or blacklist HTML tags
755 * 2. restricted tag properties: (optional) whitelist or blacklist
756 * attributes, styles and classes on a set of HTML tags.
758 * Typically, each text filter rule object does either 1 or 2, not both.
760 * The structure can be very clearly seen below:
761 * 1. use the "tags" key to list HTML tags, and set the "allow" key to
762 * either true (to allow these HTML tags) or false (to forbid these HTML
763 * tags). If you leave the "tags" key's default value (the empty array),
764 * no restrictions are applied.
765 * 2. all nested within the "restrictedTags" key: use the "tags" subkey to
766 * list HTML tags to which you want to apply property restrictions, then
767 * use the "allowed" subkey to whitelist specific property values, and
768 * similarly use the "forbidden" subkey to blacklist specific property
772 * <caption>Whitelist the "p", "strong" and "a" HTML tags.</caption>
774 * tags: ['p', 'strong', 'a'],
778 * allowed: { attributes: [], styles: [], classes: [] },
779 * forbidden: { attributes: [], styles: [], classes: [] }
783 * <caption>For the "a" HTML tag, only allow the "href" attribute
784 * and the "external" class and disallow the "target" attribute.</caption>
790 * allowed: { attributes: ['href'], styles: [], classes: ['external'] },
791 * forbidden: { attributes: ['target'], styles: [], classes: [] }
795 * <caption>For all tags, allow the "data-*" attribute (that is, any
796 * attribute that begins with "data-").</caption>
802 * allowed: { attributes: ['data-*'], styles: [], classes: [] },
803 * forbidden: { attributes: [], styles: [], classes: [] }
808 * An object with the following structure:
815 * allowed: {attributes: Array, styles: Array, classes: Array},
816 * forbidden: {attributes: Array, styles: Array, classes: Array}
821 * @see Drupal.FilterStatus
823 Drupal.FilterHTMLRule = function () {
824 // Allow or forbid tags.
828 // Apply restrictions to properties set on tags.
829 this.restrictedTags = {
831 allowed: {attributes: [], styles: [], classes: []},
832 forbidden: {attributes: [], styles: [], classes: []}
838 Drupal.FilterHTMLRule.prototype.clone = function () {
839 var clone = new Drupal.FilterHTMLRule();
840 clone.tags = this.tags.slice(0);
841 clone.allow = this.allow;
842 clone.restrictedTags.tags = this.restrictedTags.tags.slice(0);
843 clone.restrictedTags.allowed.attributes = this.restrictedTags.allowed.attributes.slice(0);
844 clone.restrictedTags.allowed.styles = this.restrictedTags.allowed.styles.slice(0);
845 clone.restrictedTags.allowed.classes = this.restrictedTags.allowed.classes.slice(0);
846 clone.restrictedTags.forbidden.attributes = this.restrictedTags.forbidden.attributes.slice(0);
847 clone.restrictedTags.forbidden.styles = this.restrictedTags.forbidden.styles.slice(0);
848 clone.restrictedTags.forbidden.classes = this.restrictedTags.forbidden.classes.slice(0);
853 * Tracks the configuration of all text filters in {@link Drupal.FilterStatus}
854 * objects for {@link Drupal.editorConfiguration.featureIsAllowedByFilters}.
858 Drupal.filterConfiguration = {
861 * Drupal.FilterStatus objects, keyed by filter ID.
863 * @type {Object.<string, Drupal.FilterStatus>}
868 * Live filter setting parsers.
870 * Object keyed by filter ID, for those filters that implement it.
872 * Filters should load the implementing JavaScript on the filter
873 * configuration form and implement
874 * `Drupal.filterSettings[filterID].getRules()`, which should return an
875 * array of {@link Drupal.FilterHTMLRule} objects.
879 liveSettingParsers: {},
882 * Updates all {@link Drupal.FilterStatus} objects to reflect current state.
884 * Automatically checks whether a filter is currently enabled or not. To
885 * support more finegrained.
887 * If a filter implements a live setting parser, then that will be used to
888 * keep the HTML rules for the {@link Drupal.FilterStatus} object
891 update: function () {
892 for (var filterID in Drupal.filterConfiguration.statuses) {
893 if (Drupal.filterConfiguration.statuses.hasOwnProperty(filterID)) {
895 Drupal.filterConfiguration.statuses[filterID].active = $('[name="filters[' + filterID + '][status]"]').is(':checked');
897 // Update current rules.
898 if (Drupal.filterConfiguration.liveSettingParsers[filterID]) {
899 Drupal.filterConfiguration.statuses[filterID].rules = Drupal.filterConfiguration.liveSettingParsers[filterID].getRules();
908 * Initializes {@link Drupal.filterConfiguration}.
910 * @type {Drupal~behavior}
912 * @prop {Drupal~behaviorAttach} attach
913 * Gets filter configuration from filter form input.
915 Drupal.behaviors.initializeFilterConfiguration = {
916 attach: function (context, settings) {
917 var $context = $(context);
919 $context.find('#filters-status-wrapper input.form-checkbox').once('filter-editor-status').each(function () {
920 var $checkbox = $(this);
921 var nameAttribute = $checkbox.attr('name');
923 // The filter's checkbox has a name attribute of the form
924 // "filters[<name of filter>][status]", parse "<name of filter>"
926 var filterID = nameAttribute.substring(8, nameAttribute.indexOf(']'));
928 // Create a Drupal.FilterStatus object to track the state (whether it's
929 // active or not and its current settings, if any) of each filter.
930 Drupal.filterConfiguration.statuses[filterID] = new Drupal.FilterStatus(filterID);
935 })(jQuery, _, Drupal, document);