Chris@0: /** Chris@0: * @file Chris@0: * CKEditor StylesCombo admin behavior. Chris@0: */ Chris@0: Chris@17: (function($, Drupal, drupalSettings, _) { Chris@0: /** Chris@0: * Ensures that the "stylescombo" button's metadata remains up-to-date. Chris@0: * Chris@0: * Triggers the CKEditorPluginSettingsChanged event whenever the "stylescombo" Chris@0: * plugin settings change, to ensure that the corresponding feature metadata Chris@0: * is immediately updated — i.e. ensure that HTML tags and classes entered Chris@0: * here are known to be "required", which may affect filter settings. Chris@0: * Chris@0: * @type {Drupal~behavior} Chris@0: * Chris@0: * @prop {Drupal~behaviorAttach} attach Chris@0: * Attaches admin behaviour to the "stylescombo" button. Chris@0: */ Chris@0: Drupal.behaviors.ckeditorStylesComboSettings = { Chris@0: attach(context) { Chris@0: const $context = $(context); Chris@0: Chris@0: // React to changes in the list of user-defined styles: calculate the new Chris@0: // stylesSet setting up to 2 times per second, and if it is different, Chris@0: // fire the CKEditorPluginSettingsChanged event with the updated parts of Chris@0: // the CKEditor configuration. (This will, in turn, cause the hidden Chris@0: // CKEditor instance to be updated and a drupalEditorFeatureModified event Chris@0: // to fire.) Chris@0: const $ckeditorActiveToolbar = $context Chris@0: .find('.ckeditor-toolbar-configuration') Chris@0: .find('.ckeditor-toolbar-active'); Chris@17: let previousStylesSet = Chris@17: drupalSettings.ckeditor.hiddenCKEditorConfig.stylesSet; Chris@0: const that = this; Chris@17: $context Chris@17: .find('[name="editor[settings][plugins][stylescombo][styles]"]') Chris@17: .on('blur.ckeditorStylesComboSettings', function() { Chris@0: const styles = $.trim($(this).val()); Chris@0: const stylesSet = that._generateStylesSetSetting(styles); Chris@0: if (!_.isEqual(previousStylesSet, stylesSet)) { Chris@0: previousStylesSet = stylesSet; Chris@0: $ckeditorActiveToolbar.trigger('CKEditorPluginSettingsChanged', [ Chris@0: { stylesSet }, Chris@0: ]); Chris@0: } Chris@0: }); Chris@0: }, Chris@0: Chris@0: /** Chris@0: * Builds the "stylesSet" configuration part of the CKEditor JS settings. Chris@0: * Chris@0: * @see \Drupal\ckeditor\Plugin\ckeditor\plugin\StylesCombo::generateStylesSetSetting() Chris@0: * Chris@0: * Note that this is a more forgiving implementation than the PHP version: Chris@0: * the parsing works identically, but instead of failing on invalid styles, Chris@0: * we just ignore those. Chris@0: * Chris@0: * @param {string} styles Chris@0: * The "styles" setting. Chris@0: * Chris@0: * @return {Array} Chris@0: * An array containing the "stylesSet" configuration. Chris@0: */ Chris@0: _generateStylesSetSetting(styles) { Chris@0: const stylesSet = []; Chris@0: Chris@0: styles = styles.replace(/\r/g, '\n'); Chris@0: const lines = styles.split('\n'); Chris@0: for (let i = 0; i < lines.length; i++) { Chris@0: const style = $.trim(lines[i]); Chris@0: Chris@0: // Ignore empty lines in between non-empty lines. Chris@0: if (style.length === 0) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: // Validate syntax: element[.class...]|label pattern expected. Chris@17: if ( Chris@17: style.match(/^ *[a-zA-Z0-9]+ *(\.[a-zA-Z0-9_-]+ *)*\| *.+ *$/) === Chris@17: null Chris@17: ) { Chris@0: // Instead of failing, we just ignore any invalid styles. Chris@0: continue; Chris@0: } Chris@0: Chris@0: // Parse. Chris@0: const parts = style.split('|'); Chris@0: const selector = parts[0]; Chris@0: const label = parts[1]; Chris@0: const classes = selector.split('.'); Chris@0: const element = classes.shift(); Chris@0: Chris@0: // Build the data structure CKEditor's stylescombo plugin expects. Chris@0: // @see http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Styles Chris@0: stylesSet.push({ Chris@0: attributes: { class: classes.join(' ') }, Chris@0: element, Chris@0: name: label, Chris@0: }); Chris@0: } Chris@0: Chris@0: return stylesSet; Chris@0: }, Chris@0: }; Chris@0: Chris@0: /** Chris@0: * Provides the summary for the "stylescombo" plugin settings vertical tab. Chris@0: * Chris@0: * @type {Drupal~behavior} Chris@0: * Chris@0: * @prop {Drupal~behaviorAttach} attach Chris@0: * Attaches summary behaviour to the plugin settings vertical tab. Chris@0: */ Chris@0: Drupal.behaviors.ckeditorStylesComboSettingsSummary = { Chris@0: attach() { Chris@17: $('[data-ckeditor-plugin-id="stylescombo"]').drupalSetSummary(context => { Chris@17: const styles = $.trim( Chris@17: $( Chris@17: '[data-drupal-selector="edit-editor-settings-plugins-stylescombo-styles"]', Chris@17: ).val(), Chris@17: ); Chris@0: if (styles.length === 0) { Chris@0: return Drupal.t('No styles configured'); Chris@0: } Chris@0: Chris@0: const count = $.trim(styles).split('\n').length; Chris@0: return Drupal.t('@count styles configured', { '@count': count }); Chris@0: }); Chris@0: }, Chris@0: }; Chris@17: })(jQuery, Drupal, drupalSettings, _);