diff -u b/editors/ckeditor.inc b/editors/ckeditor.inc --- b/editors/ckeditor.inc +++ b/editors/ckeditor.inc @@ -121,46 +121,37 @@ } /** - * Implements the 'settings form callback' callback for CKEditor. + * Enhances the editor profile settings form for CKEditor. * - * This callback: - * - Changes the description on the 'CSS Classes' element. - * - Defines an element validator on the 'CSS Classes' element. - * or - * - Hides the 'CSS Classes' element if the CKEditor version is too old. + * Adds support for CKEditor's advanced stylesSets, which are a more advanced + * implementation and combination of block formats and font styles that allow + * to adjust the HTML element, attributes, and CSS styles at once. * - * @param array $form - * An associative array containing the structure of the form. - * @param array $form_state - * A keyed array containing the current state of the form. + * @see http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Styles + * @see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html#.stylesSet */ function wysiwyg_ckeditor_settings_form(&$form, &$form_state) { $editor = wysiwyg_get_editor($form['editor']['#value']); if (version_compare($editor['installed version'], '3.2.1', '>=')) { - $form['css']['css_classes']['#description'] = t('Optionally define CSS classes for the "Font style" dropdown list.
Enter one class on each line in the format: !format. Example: !example
If left blank, CSS classes are automatically imported from all loaded stylesheet(s).', - array('!format' => '[title]=[element].[class]', '!example' => 'My heading=h1.header1')); - $form['css']['css_classes']['#element_validate'][] = 'wysiwyg_ckeditor_settings_form_css_classes_validate'; + // Replace CSS classes element description to explain the advanced syntax. + $form['css']['css_classes']['#description'] = t('Optionally define CSS classes for the "Font style" dropdown list.
Enter one class on each line in the format: !format. Example: !example
If left blank, CSS classes are automatically imported from loaded stylesheet(s).', array( + '!format' => '[label]=[element].[class]', + '!example' => 'Title=h1.title', + )); + $form['css']['css_classes']['#element_validate'][] = 'wysiwyg_ckeditor_settings_form_validate_css_classes'; } else { - // Do not show elements that do not work in the currently installed version. + // Versions below 3.2.1 do not support Font styles at all. $form['css']['css_classes']['#access'] = FALSE; } } /** - * Implements a form validator for the CSS Classes element of the settings form. - * - * @param array $element - * An associative array containing the form element to validate. - * @param array $form_state - * A keyed array containing the current state of the form. - * @param array $form - * An associative array containing the structure of the form. + * #element_validate handler for CSS classes element altered by wysiwyg_ckeditor_settings_form(). */ -function wysiwyg_ckeditor_settings_form_css_classes_validate($element, &$form_state, $form) { - $errors = wysiwyg_ckeditor_parse_styles_set($element['#value'], TRUE); - if (!empty($errors)) { - form_error($element, t('Incorrect syntax for the CSS Classes. See the description for how to use this option.')); +function wysiwyg_ckeditor_settings_form_validate_css_classes($element, &$form_state) { + if (wysiwyg_ckeditor_settings_parse_styles($element['#value']) === FALSE) { + form_error($element, t('The specified CSS classes are syntactically incorrect.')); } } @@ -233,10 +224,11 @@ } } - // Get additional styles, supported in versions 3.2.1 and above. - if (!empty($config['css_classes']) && version_compare($editor['installed version'], '3.2.1', '>=')) { - $styles = wysiwyg_ckeditor_parse_styles_set($config['css_classes']); - if (!empty($styles)) { + // Parse and define the styles set for the Styles plugin (3.2.1+). + // @todo This should be a plugin setting, but Wysiwyg does not support + // plugin-specific settings yet. + if (!empty($config['buttons']['default']['Styles']) && version_compare($editor['installed version'], '3.2.1', '>=')) { + if ($styles = wysiwyg_ckeditor_settings_parse_styles($config['css_classes'])) { $settings['stylesSet'] = $styles; } } @@ -302,6 +294,51 @@ } /** + * Parses CSS classes settings string into a stylesSet JavaScript settings array. + * + * @param string $css_classes + * A string containing CSS class definitions to add to the Style dropdown + * list, separated by newlines. + * + * @return array|false + * An array containing the parsed stylesSet definition, or FALSE on parse + * error. + * + * @see wysiwyg_ckeditor_settings_form() + * @see wysiwyg_ckeditor_settings_form_validate_css_classes() + * + * @todo This should be a plugin setting, but Wysiwyg does not support + * plugin-specific settings yet. + */ +function wysiwyg_ckeditor_settings_parse_styles($css_classes) { + $set = array(); + $input = trim($css_classes); + if (empty($input)) { + return $set; + } + // Handle both Unix and Windows line-endings. + foreach (explode("\n", str_replace("\r", '', $input)) as $line) { + $line = trim($line); + // [label]=[element].[class][.[class]][...] pattern expected. + if (!preg_match('@^.+= *[a-zA-Z0-9]+(\.[a-zA-Z0-9_ -]+)*$@', $line)) { + return FALSE; + } + list($label, $selector) = explode('=', $line, 2); + $classes = explode('.', $selector); + $element = array_shift($classes); + + $style = array(); + $style['name'] = trim($label); + $style['element'] = trim($element); + if (!empty($classes)) { + $style['attributes']['class'] = implode(' ', array_map('trim', $classes)); + } + $set[] = $style; + } + return $set; +} + +/** * Build a JS settings array of native external plugins that need to be loaded separately. */ function wysiwyg_ckeditor_plugin_settings($editor, $profile, $plugins) { @@ -400,52 +436,0 @@ -/** - * Converts the CSS classes string to an array of js settings. - * - * The CSS classes are edited in element CSS Classes, fieldset CSS - * of page admin/config/content/wysiwyg/profile/{filter}/edit. - * - * This function can also be used to just validate the CSS classes. This could - * be done in 2 separate functions, both optimized for their specific use case, - * but that would lead to more code than this single function and (more or less) - * the same logic and knowledge about the syntax in 2 places. - * - * @param string $css_classes - * A list of classes to add to the style drop down. - * @param bool $validate - * TRUE to only validate, FALSE (default) to parse. - * - * @return array - * An array with the parsed css styles or line numbers that contain incorrect - * syntax. - */ -function wysiwyg_ckeditor_parse_styles_set($css_classes, $validate = FALSE) { - $css_styles = array(); - $errors = array(); - - // Handle both Unix and Windows line-endings. - $lines = explode("\n", str_replace("\r", '', $css_classes)); - $line_no = 0; - foreach ($lines as $line) { - $line_no++; - $line = trim($line); - if (!empty($line)) { - // [name]=[element].[class] pattern expected. - $line_parts = explode('=', $line); - if (count($line_parts) === 2) { - $selector_parts = explode('.', $line_parts[1]); - if (count($selector_parts) === 2) { - $style['name'] = trim($line_parts[0]); - $style['element'] = trim($selector_parts[0]); - $style['attributes']['class'] = trim($selector_parts[1]); - if (!empty($style['name']) && !empty($style['element']) && !empty($style['attributes']['class'])) { - // This line is correct. Add it to the list and continue the loop to - // prevent it being added to the list of errors. - $css_styles[] = $style; - continue; - } - } - } - $errors[] = $line_no; - } - } - return $validate ? $errors : $css_styles; -}