diff -uprN markup_snippets_orig/markup_snippets.js markup_snippets/markup_snippets.js --- markup_snippets_orig/markup_snippets.js 1970-01-01 01:00:00.000000000 +0100 +++ markup_snippets/markup_snippets.js 2010-01-28 20:51:51.728389475 +0100 @@ -0,0 +1,61 @@ +// $Id$ + +/* + * Attach AJAX/AHAH event handlers for Wysiwyg integration. + * + * This code takes care of Wysiwyg integration in D6. + * Wysiwyg module needs to be able to detach any attached editor before the + * AJAX request is made or it cannot be re-attached afterwards. + * Drupal 6 does not have detach behaviors so we need to manually call + * Drupal.wysiwygDetach(). Wysiwyg's own behavior won't be able to + * re-attach the editor either because the context doesn't include the + * format selector so we call Drupal.wysiwygAttach() manually too. + * Drupal's jquery.form.js does not trigger 'form-pre-serialize' so we must + * re-serialize the form after detaching the editor in 'ajaxSend'. + * + * @param context + * A DOM element, supplied by Drupal.attachBehaviors(). + * + * This code is based on Drupal.behaviors.attachWysiwyg from Wysiwyg module. + * @see Drupal.behaviors.attachWysiwyg in Wysiwyg module. + */ +Drupal.behaviors.markup_snippets = function (context) { + var params; + // Add a global AJAX listener for attaching/detaching Wysiwyg module. + $('#edit-markup-snippets-select-wrapper:not(.markup-snippets-processed)', context).each(function () { + $(this).addClass('markup-snippets-processed').bind('ajaxSend', function (event, XMLHttpRequest, ajaxOptions) { + if (typeof Drupal.wysiwyg == 'undefined') { + return; + } + // Detach the Wysiwyg module if this is our request. + if (ajaxOptions.url == '/markup_snippets/js') { + params = $.extend({}, Drupal.wysiwyg.instances['edit-body']); + if (params.editor == 'none') { + // No editor instance, get parameters from the selected input format. + params = Drupal.wysiwyg.getParams($(':input.wysiwyg-field-edit-body:checked, div.wysiwyg-field-edit-body', context).get(0)); + // Override status to keep the editor disabled when re-attaching. + params.status = false; + } + Drupal.wysiwygDetach(context, params); + // Re-serialize the form. Enable the select to include its value. + $("#edit-markup-snippets-changed").attr('disabled', false); + var formValues = $('#edit-body').parents('form').formToArray(); + // Add the operation/clicked button, ahah.js normally does this for us. + formValues.push({ + name: 'op', + value: Drupal.settings.ahah['edit-markup-snippets-changed'].button.op, + }); + ajaxOptions.data = $.param(formValues); + // Disable the select and the button to avoid multiple paralell posts. + $("#edit-markup-snippets-select, #edit-markup-snippets-changed").attr('disabled', true); + } + }).bind('ajaxComplete', function (event, XMLHttpRequest, ajaxOptions) { + // Re-attach the Wysiwyg module if this is our response. + if (ajaxOptions.url == '/markup_snippets/js') { + Drupal.wysiwygAttach(context, params); + // Re-enable the select, the button is automatically enabled by ahah.js. + $("#edit-markup-snippets-select").attr('disabled', false) + } + }); + }); +} diff -uprN markup_snippets_orig/markup_snippets.module markup_snippets/markup_snippets.module --- markup_snippets_orig/markup_snippets.module 2010-01-12 20:20:00.301616772 +0100 +++ markup_snippets/markup_snippets.module 2010-01-29 03:03:56.627838630 +0100 @@ -14,6 +14,11 @@ function markup_snippets_form_alter(&$fo // make sure we're on a node form and user has permission to use snippets if ($form['#id'] == 'node-form' && user_access('use snippets')) { + if (module_exists('wysiwyg')) { + // Include the Wysiwyg module integration. + drupal_add_js(drupal_get_path('module', 'markup_snippets') . '/markup_snippets.js'); + } + // enforce caching for ahah $form['#cache'] = TRUE; @@ -21,15 +26,20 @@ function markup_snippets_form_alter(&$fo $type = node_get_types('type', $form['#node']); // set up a new fieldset above the node body field - $form['body_field']['markup_snippets'] = array( + $form['markup_snippets'] = array( '#type' => 'fieldset', '#title' => t('Mark-up Snippets'), '#description' => t('Load saved snippets or save the contents of the current !body_label field.', array('!body_label' => $type->body_label)), - '#weight' => -100, + '#weight' => -1, '#collapsible' => TRUE, '#collapsed' => TRUE, ); + if (module_exists('content')) { + // Simple fix for compatibility with CCK's field sorting. + $form['markup_snippets']['#weight'] = content_extra_field_weight($form['#node']->type, 'body_field') - 1; + } + // set variables for the select list $disabled = FALSE; $default_label = t('Select a snippet >>'); @@ -47,37 +57,65 @@ function markup_snippets_form_alter(&$fo } // render the actual form field - $form['body_field']['markup_snippets']['markup_snippets_select'] = array( + $form['markup_snippets']['markup_snippets_select'] = array( '#type' => 'select', '#title' => t('Select a snippet to use'), '#description' => $description, '#options' => $options, '#default_value' => 0, '#disabled' => $disabled, + ); + + // We need a submit button to add submit handlers to our select. + $form['markup_snippets']['markup_snippets_changed'] = array( + '#type' => 'submit', + // We do not need to render it, handler is called anyway. + '#value' => t('Use snippet'), + '#submit' => array('markup_snippets_select_submit'), '#ahah' => array( 'path' => 'markup_snippets/js', 'wrapper' => 'edit-body-wrapper', // default so not needed: 'method' => 'replace', - 'event' => 'change', ), + '#disabled' => $disabled, ); - - // we need a submit button to add submit handlers to our select - /*$form['body_field']['markup_snippets']['changed'] = array( - '#type' => 'submit', - '#value' => t('Use snippet'), - '#submit' => array('mark_snippets_select_submit'), - );*/ - // we need a field for naming our snippet - $form['body_field']['markup_snippets']['markup_snippets_name'] = array( + $form['markup_snippets']['markup_snippets_name'] = array( '#type' => 'textfield', '#title' => t('Enter a name to save the current snippet'), '#size' => 30, '#description' => t('If you enter a name in this box then the contents of the !body_label field will be saved as a snippet when you click Save.', array('!body_label' => $type->body_label)) ); - + + if ($form_state['values']['op'] == t('Use snippet')) { + // Get the selected snippet text and put it in the body. + // Doing it here keeps the cach in sync with the rendered form. + $mid = $form_state['values']['markup_snippets_select']; + if ($mid > 0) { + $snippets = markup_snippets_get_snippets(array(), TRUE, $mid); + // This is set to become a system variable later so you can choose to + // append or replace the snippet to the current contents. + $append = FALSE; + if ($append){ + $form['body_field']['body']['#default_value'] = $form_state['values']['body'] . $snippets[$mid]['snippet']; + } + else { + $form['body_field']['body']['#default_value'] = $snippets[$mid]['snippet']; + } + } + else { + // If no snippet was selected, override the body using just the posted + // value or the old teaser from an edited node may be prepended. + $form['body_field']['body']['#default_value'] = $form_state['values']['body']; + } + // Teaser is always 'included' in the snippet. + $form['body_field']['teaser_include']['#default_value'] = TRUE; + if (isset($form_state['post']['original_action'])) { + // #action was changed because system.module set it to request_uri(). + $form['#action'] = $form_state['post']['original_action']; + } + } } } @@ -399,6 +437,20 @@ function markup_snippets_get_snippets($s return $snippets; } +/* + * Custom submit handler for markup snippet changes. + */ +function markup_snippets_select_submit($form, &$form_state) { + // Remove form-level handlers so the node is not saved during AHAH requests. + unset($form_state['submit_handlers']); + // We still allow element level submit handlers to run. + form_execute_handlers('submit', $form, $form_state); + $node = $form_state['values']; + // Set $form_state['node'] for the node form builder. + $form_state['node'] = $node; + $form_state['rebuild'] = TRUE; +} + /** * Implementation of ahah callback for node form. */ @@ -415,10 +467,7 @@ function markup_snippets_js() { // causes an error because the node gets locked. // Preparing to retrieve form from cache - // Old line: - // $form_state = array('storage' => NULL, 'submitted' => FALSE); - // Our replacement: - $form_state = array('storage' => NULL, 'rebuild' => TRUE); + $form_state = array('storage' => NULL, 'submitted' => FALSE); $form_build_id = $_POST['form_build_id']; // Retrieve the form from the cache @@ -430,6 +479,10 @@ function markup_snippets_js() { $form_state['post'] = $form['#post'] = $_POST; $form['#programmed'] = $form['#redirect'] = FALSE; + _markup_snippets_remove_required_flag($form); + + // Store the #action, system.module will overwrite it using request_uri(). + $form_state['post']['original_action'] = $form['#action']; // Process the form drupal_process_form($form_id, $form, $form_state); // Rebuild the form @@ -438,53 +491,14 @@ function markup_snippets_js() { // CUSTOM CODE STARTS HERE // Now we have the latest $form, with the changes made by our - // AHAH enabled field - we can now build our mark-up to return - - // get the node type info we need for our body field - $node = $form['#node']; - $type = node_get_types('type', $node); - - // load the snippet from the posted data - $mid = $form_state['post']['markup_snippets_select']; - $snippet = markup_snippets_get_snippets(array(), TRUE, $mid); - - // build our new body - // this is set to become a system variable later so you can choose to - // append or replace - $append = TRUE; - if ($append && $form_state['post']['body']) { - $body_new = $form_state['post']['body'] . $snippet[$mid]['snippet']; - } - else { - $body_new = $snippet[$mid]['snippet']; - } - - // Check if we need to restore the teaser at the beginning of the body. - $include = !isset($node->teaser) || ($node->teaser == substr($node->body, 0, strlen($node->teaser))); - - // build the returned mark-up, structure from node.module - $body_form['body_field']['body'] = array( - '#type' => 'textarea', - '#title' => check_plain($type->body_label), - '#default_value' => $include, - '#value' => $body_new, - '#rows' => 20, - '#required' => ($type->min_word_count > 0), - ); - - $output = drupal_render($body_form); - - // build the returned mark-up - // we are mimicking the output of the node_get_body() function - $output = ''; - $output .= ''; - $output .= '
'; - $output .= ''; - $output .= '
'; - + // AHAH enabled field - we can now render and return the body markup. + + $changed_field = $form['body_field']['body']; + $output = drupal_render($changed_field); + // Strip the wrapper div as only its contents need to be replaced. + $output = preg_replace('/^/', '', $output); + $output = preg_replace('/<\/div>\s*$/', '', $output); + // ALL DONE // Final rendering callback - send our mark-up back to the div we @@ -495,3 +509,19 @@ function markup_snippets_js() { drupal_get_messages(); } +/** + * Helper function to recursively switch #reqiured to FALSE on form elements. + * + * When processing forms during an AHAH request we don't want to treat empty + * fields as invalid. Setting #required to FALSE makes sure our submit handler + * runs. As the form is not actually submitted to the database yet, this is ok. + */ +function _markup_snippets_remove_required_flag(&$element) { + foreach (element_children($element) as $key) { + _markup_snippets_remove_required_flag($element[$key]); + } + if (isset($element['#required']) && $element['#required']) { + $element['#required'] = FALSE; + } +} +