diff --git editors/ckeditor.inc editors/ckeditor.inc index 8ac3ceb..808b4c1 100644 --- editors/ckeditor.inc +++ editors/ckeditor.inc @@ -28,6 +28,9 @@ function wysiwyg_ckeditor_editor() { ), ), ), + 'toolbar groups' => TRUE, + 'toolbar rows' => TRUE, + 'toolbar separator' => TRUE, 'version callback' => 'wysiwyg_ckeditor_version', 'themes callback' => 'wysiwyg_ckeditor_themes', 'settings callback' => 'wysiwyg_ckeditor_settings', @@ -189,52 +192,74 @@ function wysiwyg_ckeditor_settings($editor, $config, $theme) { $settings['toolbarLocation'] = $config['toolbar_loc']; } - if (!empty($config['buttons'])) { - $extra_plugins = array(); - $settings['toolbar'] = array(); - $plugins = wysiwyg_get_plugins($editor['name']); - foreach ($config['buttons'] as $plugin => $buttons) { - foreach ($buttons as $button => $enabled) { - // Iterate separately over buttons and extensions properties. - foreach (array('buttons', 'extensions') as $type) { - // Skip unavailable plugins. - if (!isset($plugins[$plugin][$type][$button])) { - continue; - } - // Add buttons. - if ($type == 'buttons') { - $settings['toolbar'][] = $button; - } - // Add external Drupal plugins to the list of extensions. - if ($type == 'buttons' && !empty($plugins[$plugin]['proxy'])) { - $extra_plugins[] = $button; - } - // Add external plugins to the list of extensions. - elseif ($type == 'buttons' && empty($plugins[$plugin]['internal'])) { - $extra_plugins[] = $plugin; - } - // Add internal buttons that also need to be loaded as extension. - elseif ($type == 'buttons' && !empty($plugins[$plugin]['load'])) { - $extra_plugins[] = $plugin; - } - // Add plain extensions. - elseif ($type == 'extensions' && !empty($plugins[$plugin]['load'])) { - $extra_plugins[] = $plugin; - } - // Allow plugins to add or override global configuration settings. - if (!empty($plugins[$plugin]['options'])) { - $settings = array_merge($settings, $plugins[$plugin]['options']); - } - } + $extra_plugins = array(); + $toolbar = array(); + $plugins = wysiwyg_get_plugins($editor['name']); + + foreach ((array)$config['extensions'] as $plugin => $buttons) { + foreach ($buttons as $button => $enabled) { + if (!isset($plugins[$plugin]['extensions'][$button])) { + continue; + } + + // Add plain extensions. + if (!empty($plugins[$plugin]['load'])) { + $extra_plugins[] = $plugin; + } + + // Allow plugins to add or override global configuration settings. + if (!empty($plugins[$plugin]['options'])) { + $settings = array_merge($settings, $plugins[$plugin]['options']); } } - if (!empty($extra_plugins)) { - $settings['extraPlugins'] = implode(',', $extra_plugins); - } - // For now, all buttons are placed into one row. - if (!empty($settings['toolbar'])) { - $settings['toolbar'] = array($settings['toolbar']); + } + + foreach ((array)$config['toolbar'] as $row) { + foreach ($row as $buttons) { + $group = array(); + + foreach ($buttons as $button_config) { + $plugin = $button_config['plugin']; + $button = $button_config['button']; + + if ($button == 'separator') { + $group[] = '-'; + continue; + } + if (!isset($plugins[$plugin]['buttons'][$button])) { + continue; + } + + $group[] = $button; + + // Add external Drupal plugins to the list of extensions. + if (!empty($plugins[$plugin]['proxy']) || empty($plugins[$plugin]['internal']) || !empty($plugins[$plugin]['load'])) { + $extra_plugins[] = $button; + } + + // Allow plugins to add or override global configuration settings. + if (!empty($plugins[$plugin]['options'])) { + $settings = array_merge($settings, $plugins[$plugin]['options']); + } + } + + $toolbar[] = $group; } + + $toolbar[] = '/'; // toolbar line break + } + + // Remove the last '/'. + if (end($toolbar) == '/') { + array_pop($toolbar); + } + + if (!empty($extra_plugins)) { + $settings['extraPlugins'] = implode(',', array_unique($extra_plugins)); + } + + if (!empty($toolbar)) { + $settings['toolbar'] = $toolbar; } return $settings; diff --git editors/fckeditor.inc editors/fckeditor.inc index 3da106c..a5a527f 100644 --- editors/fckeditor.inc +++ editors/fckeditor.inc @@ -20,6 +20,9 @@ function wysiwyg_fckeditor_editor() { 'files' => array('fckeditor.js'), ), ), + 'toolbar groups' => TRUE, + 'toolbar rows' => TRUE, + 'toolbar separator' => TRUE, 'version callback' => 'wysiwyg_fckeditor_version', 'themes callback' => 'wysiwyg_fckeditor_themes', 'settings callback' => 'wysiwyg_fckeditor_settings', @@ -132,40 +135,66 @@ function wysiwyg_fckeditor_settings($editor, $config, $theme) { if ($config['css_setting'] == 'theme') { $settings['EditorAreaCSS'] = implode(',', wysiwyg_get_css()); } - else if ($config['css_setting'] == 'self' && isset($config['css_path'])) { + elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) { $settings['EditorAreaCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme())); } } - if (!empty($config['buttons'])) { - // Use our custom toolbar set. - $settings['ToolbarSet'] = 'Wysiwyg'; - // Populate our custom toolbar set for fckeditor.config.js. - $settings['buttons'] = array(); - $plugins = wysiwyg_get_plugins($editor['name']); - foreach ($config['buttons'] as $plugin => $buttons) { - foreach ($buttons as $button => $enabled) { - // Iterate separately over buttons and extensions properties. - foreach (array('buttons', 'extensions') as $type) { - // Skip unavailable plugins. - if (!isset($plugins[$plugin][$type][$button])) { - continue; - } - // Add buttons. - if ($type == 'buttons') { - $settings['buttons'][] = $button; - } - // Allow plugins to add or override global configuration settings. - if (!empty($plugins[$plugin]['options'])) { - $settings = array_merge($settings, $plugins[$plugin]['options']); - } - } + $plugins = wysiwyg_get_plugins($editor['name']); + $toolbar = array(); + + foreach ((array)$config['extensions'] as $plugin => $buttons) { + foreach ($buttons as $button => $enabled) { + if (!isset($plugins[$plugin]['extensions'][$button])) { + continue; + } + + // Allow plugins to add or override global configuration settings. + if (!empty($plugins[$plugin]['options'])) { + $settings = array_merge($settings, $plugins[$plugin]['options']); } } - // For now, all buttons are placed into one row. - if (!empty($settings['buttons'])) { - $settings['buttons'] = array($settings['buttons']); + } + + foreach ((array)$config['toolbar'] as $row) { + foreach ($row as $buttons) { + $group = array(); + + foreach ($buttons as $button_config) { + $plugin = $button_config['plugin']; + $button = $button_config['button']; + + if ($button == 'separator') { + $group[] = '-'; + continue; + } + if (!isset($plugins[$plugin]['buttons'][$button])) { + continue; + } + + $group[] = $button; + + // Allow plugins to add or override global configuration settings. + if (!empty($plugins[$plugin]['options'])) { + $settings = array_merge($settings, $plugins[$plugin]['options']); + } + } + + $toolbar[] = $group; } + + $toolbar[] = '/'; + } + + // Remove the last '/'. + if (end($toolbar) == '/') { + array_pop($toolbar); + } + + if (!empty($toolbar)) { + // Use our custom toolbar set. + $settings['ToolbarSet'] = 'DrupalWysiwyg'; + $settings['ToolbarSets']['DrupalWysiwyg'] = $toolbar; } return $settings; diff --git editors/js/fckeditor.config.js editors/js/fckeditor.config.js index 2c3415f..549bcfb 100644 --- editors/js/fckeditor.config.js +++ editors/js/fckeditor.config.js @@ -17,28 +17,7 @@ var pluginSettings = Drupal.settings.wysiwyg.plugins[wysiwygFormat]; * Apply format-specific settings. */ for (var setting in wysiwygSettings) { - if (setting == 'buttons') { - // Apply custom Wysiwyg toolbar for this format. - // FCKConfig.ToolbarSets['Wysiwyg'] = wysiwygSettings.buttons; - - // Temporarily stack buttons into multiple button groups and remove - // separators until #277954 is solved. - FCKConfig.ToolbarSets['Wysiwyg'] = []; - for (var i = 0; i < wysiwygSettings.buttons[0].length; i++) { - FCKConfig.ToolbarSets['Wysiwyg'].push([wysiwygSettings.buttons[0][i]]); - } - FCKTools.AppendStyleSheet(document, '#xToolbar .TB_Start { display:none; }'); - // Set valid height of select element in silver and office2003 skins. - if (FCKConfig.SkinPath.match(/\/office2003\/$/)) { - FCKTools.AppendStyleSheet(document, '#xToolbar .SC_FieldCaption { height: 24px; } #xToolbar .TB_End { display: none; }'); - } - else if (FCKConfig.SkinPath.match(/\/silver\/$/)) { - FCKTools.AppendStyleSheet(document, '#xToolbar .SC_FieldCaption { height: 27px; }'); - } - } - else { - FCKConfig[setting] = wysiwygSettings[setting]; - } + FCKConfig[setting] = wysiwygSettings[setting]; } /** diff --git editors/js/tinymce-3.js editors/js/tinymce-3.js index c90ffd5..833b1ec 100644 --- editors/js/tinymce-3.js +++ editors/js/tinymce-3.js @@ -55,15 +55,7 @@ Drupal.wysiwyg.editor.attach.tinymce = function(context, params, settings) { ed.onEvent.add(function(ed, e) { Drupal.wysiwyg.activeId = ed.id; }); - // Make toolbar buttons wrappable (required for IE). - ed.onPostRender.add(function (ed) { - var $toolbar = $('
'); - $('#' + ed.editorContainer + ' table.mceToolbar > tbody > tr > td').each(function () { - $('').addClass(this.className).append($(this).children()).appendTo($toolbar); - }); - $('#' + ed.editorContainer + ' table.mceLayout td.mceToolbar').append($toolbar); - $('#' + ed.editorContainer + ' table.mceToolbar').remove(); - }); + // Attach editor. ed.render(); }; diff --git editors/markitup.inc editors/markitup.inc index d4e6e5b..b3b0b19 100644 --- editors/markitup.inc +++ editors/markitup.inc @@ -147,11 +147,13 @@ function wysiwyg_markitup_settings($editor, $config, $theme) { 'call' => 'preview', ), ); - if (!empty($config['buttons'])) { - foreach ($config['buttons'] as $plugin) { - foreach ($plugin as $button => $enabled) { - if (isset($default_buttons[$button])) { - $settings['markupSet'][$button] = $default_buttons[$button]; + if (!empty($config['toolbar'])) { + $settings['markupSet'] = array(); + + foreach ($config['toolbar'] as $row) { + foreach ($row as $group) { + foreach ($group as $button) { + $settings['markupSet'][$button['button']] = $default_buttons[$button['button']]; } } } diff --git editors/nicedit.inc editors/nicedit.inc index 30ce42d..ce86839 100644 --- editors/nicedit.inc +++ editors/nicedit.inc @@ -66,12 +66,16 @@ function wysiwyg_nicedit_settings($editor, $config, $theme) { ); // Add configured buttons or all available. - if (!empty($config['buttons'])) { + if (!empty($config['toolbar'])) { $buttons = array(); - foreach ($config['buttons'] as $plugin) { - $buttons = array_merge($buttons, $plugin); + foreach ($config['toolbar'] as $row) { + foreach ($row as $group) { + foreach ($group as $button) { + $buttons[] = $button['button']; + } + } } - $settings['buttonList'] = array_keys($buttons); + $settings['buttonList'] = $buttons; } else { $settings['fullPanel'] = TRUE; @@ -85,7 +89,7 @@ function wysiwyg_nicedit_settings($editor, $config, $theme) { $settings['externalCSS'] = base_path() . $css; } } - else if ($config['css_setting'] == 'self' && isset($config['css_path'])) { + elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) { $settings['externalCSS'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme())); } } diff --git editors/openwysiwyg.inc editors/openwysiwyg.inc index fa2c411..58a24b8 100644 --- editors/openwysiwyg.inc +++ editors/openwysiwyg.inc @@ -21,6 +21,8 @@ function wysiwyg_openwysiwyg_editor() { 'files' => array('wysiwyg.js'), ), ), + 'toolbar rows' => TRUE, + 'toolbar separator' => TRUE, 'version callback' => 'wysiwyg_openwysiwyg_version', 'themes callback' => 'wysiwyg_openwysiwyg_themes', 'settings callback' => 'wysiwyg_openwysiwyg_settings', @@ -108,25 +110,36 @@ function wysiwyg_openwysiwyg_settings($editor, $config, $theme) { } } - if (!empty($config['buttons'])) { + if (!empty($config['toolbar'])) { + $toolbar = array(); $plugins = wysiwyg_get_plugins($editor['name']); - foreach ($config['buttons'] as $plugin => $buttons) { - foreach ($buttons as $button => $enabled) { - foreach (array('buttons', 'extensions') as $type) { + foreach ($config['toolbar'] as $row) { + $toolbar_row = array(); + + foreach ($row as $buttons) { + foreach ($buttons as $button_config) { // Skip unavailable plugins. - if (!isset($plugins[$plugin][$type][$button])) { - continue; + $plugin = $button_config['plugin']; + $button = $button_config['button']; + + if ($button == 'separator') { + $toolbar_row[] = 'seperator'; } - // Add buttons. - if ($type == 'buttons') { - $settings['Toolbar'][0][] = $button; + elseif (!isset($plugins[$plugin]['buttons'][$button])) { + continue; } + + $toolbar_row[] = $button; } } + + $toolbar[] = $toolbar_row; } + + $settings['Toolbar'] = $toolbar; } - // @todo + // @todo // if (isset($config['block_formats'])) { // $settings['DropDowns']['headings']['elements'] = explode(',', $config['block_formats']); // } diff --git editors/tinymce.inc editors/tinymce.inc index fad0c2d..89a85ad 100644 --- editors/tinymce.inc +++ editors/tinymce.inc @@ -27,6 +27,8 @@ function wysiwyg_tinymce_editor() { 'files' => array('tiny_mce_src.js'), ), ), + 'toolbar rows' => TRUE, + 'toolbar separator' => TRUE, 'version callback' => 'wysiwyg_tinymce_version', 'themes callback' => 'wysiwyg_tinymce_themes', 'settings callback' => 'wysiwyg_tinymce_settings', @@ -191,75 +193,88 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) { if ($config['css_setting'] == 'theme') { $settings['content_css'] = implode(',', wysiwyg_get_css()); } - else if ($config['css_setting'] == 'self' && isset($config['css_path'])) { + elseif ($config['css_setting'] == 'self' && isset($config['css_path'])) { $settings['content_css'] = strtr($config['css_path'], array('%b' => base_path(), '%t' => path_to_theme())); } } - // Find the enabled buttons and the button row they belong on. - // Also map the plugin metadata for each button. - // @todo What follows is a pain; needs a rewrite. - if (!empty($config['buttons']) && is_array($config['buttons'])) { - // $settings['buttons'] are stacked into - // $settings['theme_advanced_buttons1'] later. - // @todo Add a toolbar designer based on jQuery UI. - $settings['buttons'] = array(); - // Only array keys in $settings['extensions'] matter; added to - // $settings['plugins'] later. - $settings['extensions'] = array(); - // $settings['extended_valid_elements'] are just stacked, unique'd later, - // and transformed into a comma-separated string in - // wysiwyg_add_editor_settings(). - // @todo Needs a complete plugin API redesign using arrays for - // tag => attributes definitions and array_merge_recursive(). - $settings['extended_valid_elements'] = array(); + $plugins = wysiwyg_get_plugins($editor['name']); + $settings['extended_valid_elements'] = array(); + $toolbar = array(); + $extensions = array(); - $plugins = wysiwyg_get_plugins($editor['name']); - foreach ($config['buttons'] as $plugin => $buttons) { - foreach ($buttons as $button => $enabled) { - // Iterate separately over buttons and extensions properties. - foreach (array('buttons', 'extensions') as $type) { - // Skip unavailable plugins. - if (!isset($plugins[$plugin][$type][$button])) { - continue; - } - // Add buttons. - if ($type == 'buttons') { - $settings['buttons'][] = $button; - } - // Add external Drupal plugins to the list of extensions. - if ($type == 'buttons' && !empty($plugins[$plugin]['proxy'])) { - $settings['extensions'][_wysiwyg_tinymce_plugin_name('add', $button)] = 1; - } - // Add external plugins to the list of extensions. - else if ($type == 'buttons' && empty($plugins[$plugin]['internal'])) { - $settings['extensions'][_wysiwyg_tinymce_plugin_name('add', $plugin)] = 1; - } - // Add internal buttons that also need to be loaded as extension. - else if ($type == 'buttons' && !empty($plugins[$plugin]['load'])) { - $settings['extensions'][$plugin] = 1; - } - // Add plain extensions. - else if ($type == 'extensions' && !empty($plugins[$plugin]['load'])) { - $settings['extensions'][$plugin] = 1; - } - // Allow plugins to add valid HTML elements. - if (!empty($plugins[$plugin]['extended_valid_elements'])) { - $settings['extended_valid_elements'] = array_merge($settings['extended_valid_elements'], $plugins[$plugin]['extended_valid_elements']); - } - // Allow plugins to add or override global configuration settings. - if (!empty($plugins[$plugin]['options'])) { - $settings = array_merge($settings, $plugins[$plugin]['options']); - } - } + foreach ((array)$config['extensions'] as $plugin => $buttons) { + foreach ($buttons as $button => $enabled) { + if (!isset($plugins[$plugin], $plugins[$plugin]['extensions'], $plugins[$plugin]['extensions'][$button])) { + continue; + } + + // Add plain extensions. + if (!empty($plugins[$plugin]['load'])) { + $extensions[$plugin] = 1; + } + + // Allow plugins to add valid HTML elements. + if (!empty($plugins[$plugin]['extended_valid_elements'])) { + $settings['extended_valid_elements'] = array_merge($settings['extended_valid_elements'], $plugins[$plugin]['extended_valid_elements']); + } + + // Allow plugins to add or override global configuration settings. + if (!empty($plugins[$plugin]['options'])) { + $settings = array_merge($settings, $plugins[$plugin]['options']); } } - // Clean-up. - $settings['extended_valid_elements'] = array_unique($settings['extended_valid_elements']); - if ($settings['extensions']) { - $settings['plugins'] = array_keys($settings['extensions']); + } + + foreach ((array)$config['toolbar'] as $row) { + $group = array(); + + foreach ($row as $buttons) { + foreach ($buttons as $button_config) { + $plugin = $button_config['plugin']; + $button = $button_config['button']; + + if ($button == 'separator') { + $group[] = '|'; + continue; + } + if (!isset($plugins[$plugin]['buttons'][$button])) { + continue; + } + + $group[] = $button; + + // Add external Drupal plugins to the list of extensions. + if (!empty($plugins[$plugin]['proxy'])) { + $extensions[_wysiwyg_tinymce_plugin_name('add', $button)] = 1; + } + // Add external plugins to the list of extensions. + elseif (empty($plugins[$plugin]['internal'])) { + $extensions[_wysiwyg_tinymce_plugin_name('add', $plugin)] = 1; + } + // Add internal buttons that also need to be loaded as extension. + elseif (!empty($plugins[$plugin]['load'])) { + $extensions[$plugin] = 1; + } + + // Allow plugins to add or override global configuration settings. + if (!empty($plugins[$plugin]['options'])) { + $settings = array_merge($settings, $plugins[$plugin]['options']); + } + + // Allow plugins to add valid HTML elements. + if (!empty($plugins[$plugin]['extended_valid_elements'])) { + $settings['extended_valid_elements'] = array_merge($settings['extended_valid_elements'], $plugins[$plugin]['extended_valid_elements']); + } + } } - unset($settings['extensions']); + + $toolbar[] = $group; + } + + $settings['extended_valid_elements'] = array_unique($settings['extended_valid_elements']); + if ($extensions) { + $settings['plugins'] = array_keys($extensions); } // Add theme-specific settings. @@ -276,7 +291,7 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) { if (isset($config['block_formats'])) { $settings['theme_advanced_blockformats'] = $config['block_formats']; } - if (isset($settings['buttons'])) { + if ($toolbar) { // These rows explicitly need to be set to be empty, otherwise TinyMCE // loads its default buttons of the advanced theme for each row. $settings += array( @@ -284,14 +299,17 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) { 'theme_advanced_buttons2' => array(), 'theme_advanced_buttons3' => array(), ); - // @todo Allow to sort/arrange editor buttons. - for ($i = 0; $i < count($settings['buttons']); $i++) { - $settings['theme_advanced_buttons1'][] = $settings['buttons'][$i]; + + for ($i = 0;$i < count($toolbar);$i++) { + $group = $toolbar[$i]; + + foreach ($group as $button) { + $settings['theme_advanced_buttons' . ($i+1)][] = $button; + } } } break; } - unset($settings['buttons']); // Convert the config values into the form expected by TinyMCE. foreach ($settings as $key => $value) { diff --git images/add.png images/add.png new file mode 100644 index 0000000..6332fef Binary files /dev/null and images/add.png differ diff --git images/draggable.png images/draggable.png new file mode 100644 index 0000000..47e8a02 Binary files /dev/null and images/draggable.png differ diff --git wysiwyg-toolbar-designer.tpl.php wysiwyg-toolbar-designer.tpl.php new file mode 100644 index 0000000..8d9cd8c --- /dev/null +++ wysiwyg-toolbar-designer.tpl.php @@ -0,0 +1,33 @@ + diff --git wysiwyg.admin.inc wysiwyg.admin.inc index 26e3b6f..d707a05 100644 --- wysiwyg.admin.inc +++ wysiwyg.admin.inc @@ -7,9 +7,9 @@ */ /** - * Form builder for Wysiwyg profile form. + * Prepare default properties for profile. */ -function wysiwyg_profile_form($form_state, $profile) { +function wysiwyg_profile_default($profile) { // Merge in defaults. $profile = (array) $profile; $profile += array( @@ -46,10 +46,21 @@ function wysiwyg_profile_form($form_state, $profile) { ); $profile = (object) $profile; + return $profile; +} + +/** + * Form builder for Wysiwyg profile form. + */ +function wysiwyg_profile_form($form_state, $profile) { + $profile = wysiwyg_profile_default($profile); + $formats = filter_formats(); $editor = wysiwyg_get_editor($profile->editor); drupal_set_title(t('%editor profile for %format', array('%editor' => $editor['title'], '%format' => $formats[$profile->format]->name))); + $form_state['storage']['profile'] = $profile; + $form['format'] = array('#type' => 'value', '#value' => $profile->format); $form['input_format'] = array('#type' => 'value', '#value' => $formats[$profile->format]->name); $form['editor'] = array('#type' => 'value', '#value' => $profile->editor); @@ -98,51 +109,91 @@ function wysiwyg_profile_form($form_state, $profile) { '#description' => t('The language to use for the editor interface. Language codes are based on the ISO-639-2 format.'), ); - $form['buttons'] = array( + $form['extensions'] = array( '#type' => 'fieldset', - '#title' => t('Buttons and plugins'), + '#title' => t('Extensions'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#tree' => TRUE, '#theme' => 'wysiwyg_admin_button_table', ); + // Get all available buttons. $plugins = wysiwyg_get_plugins($profile->editor); - // Generate the button list. + $buttons = array(); + + // Generate the extensions list and button array. foreach ($plugins as $name => $meta) { - if (isset($meta['buttons']) && is_array($meta['buttons'])) { - foreach ($meta['buttons'] as $button => $title) { - $icon = ''; - if (!empty($meta['path'])) { - // @todo Button icon locations are different in editors, editor versions, - // and contrib/custom plugins (like Image Assist, f.e.). - $img_src = $meta['path'] . "/images/$name.gif"; - // Handle plugins that have more than one button. - if (!file_exists($img_src)) { - $img_src = $meta['path'] . "/images/$button.gif"; - } - $icon = file_exists($img_src) ? ' + + + +