core/modules/ckeditor/js/views/ControllerView.js | 5 +++- core/modules/editor/js/editor.admin.js | 33 +++++++++++++++++------- core/modules/filter/filter.filter_html.admin.js | 33 +++++++++++++++++++----- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/core/modules/ckeditor/js/views/ControllerView.js b/core/modules/ckeditor/js/views/ControllerView.js index f1c4ddf..6234be1 100644 --- a/core/modules/ckeditor/js/views/ControllerView.js +++ b/core/modules/ckeditor/js/views/ControllerView.js @@ -221,6 +221,9 @@ // the feature that was just added or removed. Not every feature has // such metadata. var featureName = this.model.get('buttonsToFeatures')[button.toLowerCase()]; + if (!featureName) { + featureName = button.toLowerCase(); + } var featuresMetadata = this.model.get('featuresMetadata'); if (!featuresMetadata[featureName]) { featuresMetadata[featureName] = new Drupal.EditorFeature(featureName); @@ -301,7 +304,6 @@ broadcastConfigurationChanges: function ($ckeditorToolbar) { var view = this; var hiddenEditorConfig = this.model.get('hiddenEditorConfig'); - var featuresMetadata = this.model.get('featuresMetadata'); var getFeatureForButton = this.getFeatureForButton.bind(this); var getCKEditorFeatures = this.getCKEditorFeatures.bind(this); $ckeditorToolbar @@ -335,6 +337,7 @@ getCKEditorFeatures(hiddenEditorConfig, function (features) { // Trigger a standardized text editor configuration event for each // feature that was modified by the configuration changes. + var featuresMetadata = view.model.get('featuresMetadata'); for (var name in features) { if (features.hasOwnProperty(name)) { var feature = features[name]; diff --git a/core/modules/editor/js/editor.admin.js b/core/modules/editor/js/editor.admin.js index 14599d0..bc7ebcc 100644 --- a/core/modules/editor/js/editor.admin.js +++ b/core/modules/editor/js/editor.admin.js @@ -821,17 +821,32 @@ * @see Drupal.FilterStatus */ Drupal.FilterHTMLRule = function () { - return { - // Allow or forbid tags. + // Allow or forbid tags. + this.tags = []; + this.allow = null; + + // Apply restrictions to properties set on tags. + this.restrictedTags = { tags: [], - allow: null, - // Apply restrictions to properties set on tags. - restrictedTags: { - tags: [], - allowed: {attributes: [], styles: [], classes: []}, - forbidden: {attributes: [], styles: [], classes: []} - } + allowed: {attributes: [], styles: [], classes: []}, + forbidden: {attributes: [], styles: [], classes: []} }; + + return this; + }; + + Drupal.FilterHTMLRule.prototype.clone = function () { + var clone = new Drupal.FilterHTMLRule(); + clone.tags = this.tags.slice(0); + clone.allow = this.allow; + clone.restrictedTags.tags = this.restrictedTags.tags.slice(0); + clone.restrictedTags.allowed.attributes = this.restrictedTags.allowed.attributes.slice(0); + clone.restrictedTags.allowed.styles = this.restrictedTags.allowed.styles.slice(0); + clone.restrictedTags.allowed.classes = this.restrictedTags.allowed.classes.slice(0); + clone.restrictedTags.forbidden.attributes = this.restrictedTags.forbidden.attributes.slice(0); + clone.restrictedTags.forbidden.styles = this.restrictedTags.forbidden.styles.slice(0); + clone.restrictedTags.forbidden.classes = this.restrictedTags.forbidden.classes.slice(0); + return clone; }; /** diff --git a/core/modules/filter/filter.filter_html.admin.js b/core/modules/filter/filter.filter_html.admin.js index 8f94d44..ace83f2 100644 --- a/core/modules/filter/filter.filter_html.admin.js +++ b/core/modules/filter/filter.filter_html.admin.js @@ -157,7 +157,8 @@ // Drupal.EditorFeatureHTMLRule allow for generic attribute // value restrictions, only for the "class" and "style" // attribute's values to be restricted. - filterRule.restrictedTags.allowed.attributes = featureRule.required.attributes; + filterRule.restrictedTags.allowed.attributes = featureRule.required.attributes.slice(0); + filterRule.restrictedTags.allowed.classes = featureRule.required.classes.slice(0); editorRequiredTags[tag] = filterRule; } // The tag is already allowed, add any additionally allowed @@ -165,6 +166,7 @@ else { filterRule = editorRequiredTags[tag]; filterRule.restrictedTags.allowed.attributes = _.union(filterRule.restrictedTags.allowed.attributes, featureRule.required.attributes); + filterRule.restrictedTags.allowed.classes = _.union(filterRule.restrictedTags.allowed.classes, featureRule.required.classes); } } } @@ -184,14 +186,24 @@ autoAllowedTags[tag] = editorRequiredTags[tag]; } // Otherwise, if userAllowedTags already allows this tag, then check if - // additional attributes on this tag are required by the editor. + // additional attributes and classes on this tag are required by the + // editor. else { var requiredAttributes = editorRequiredTags[tag].restrictedTags.allowed.attributes; var allowedAttributes = userAllowedTags[tag].restrictedTags.allowed.attributes; - if (requiredAttributes.length &&_.difference(requiredAttributes, allowedAttributes).length) { - autoAllowedTags[tag] = userAllowedTags[tag]; + var needsAdditionalAttributes= requiredAttributes.length &&_.difference(requiredAttributes, allowedAttributes).length; + var requiredClasses = editorRequiredTags[tag].restrictedTags.allowed.classes; + var allowedClasses = userAllowedTags[tag].restrictedTags.allowed.classes; + var needsAdditionalClasses = requiredClasses.length &&_.difference(requiredClasses, allowedClasses).length; + if (needsAdditionalAttributes || needsAdditionalClasses) { + autoAllowedTags[tag] = userAllowedTags[tag].clone(); + } + if (needsAdditionalAttributes) { autoAllowedTags[tag].restrictedTags.allowed.attributes = _.union(allowedAttributes, requiredAttributes); } + if (needsAdditionalClasses) { + autoAllowedTags[tag].restrictedTags.allowed.classes = _.union(allowedClasses, requiredClasses); + } // @todo attribute values. } } @@ -233,8 +245,13 @@ // @todo Drupal.FilterHtmlRule does not allow for generic attribute // value restrictions, only for the "class" and "style" attribute's // values. - var attributeValue = attribute.textContent; - rule.restrictedTags.allowed.attributes.push(attributeName); + if (attributeName === 'class') { + var attributeValue = attribute.textContent; + rule.restrictedTags.allowed.classes = attributeValue.split(' '); + } + else { + rule.restrictedTags.allowed.attributes.push(attributeName); + } } rules[tag] = rule; @@ -261,6 +278,10 @@ if (rule.restrictedTags.allowed.attributes.length) { setting += ' ' + rule.restrictedTags.allowed.attributes.join(' '); } + if (rule.restrictedTags.allowed.classes.length) { + setting += ' class="' + rule.restrictedTags.allowed.classes.join(' ') + '"'; + } + // @todo Drupal.FilterHtmlRule does not allow for generic attribute // value restrictions, only for the "class" and "style" attribute's // values. Until generic support is here, we don't bother generating