? live_d5_node_preview.patch
? node
Index: live.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/live/live.info,v
retrieving revision 1.1.2.6
diff -u -p -r1.1.2.6 live.info
--- live.info 4 Feb 2008 20:01:05 -0000 1.1.2.6
+++ live.info 24 Oct 2008 11:19:24 -0000
@@ -1,4 +1,9 @@
; $Id: live.info,v 1.1.2.6 2008/02/04 20:01:05 Gurpartap Exp $
name = Live
description = Preview nodes and comments instantly, while authoring. Returns content securely from an Ajax call, viz filtered based upon the selected Input Format.
-package = Javascript
\ No newline at end of file
+package = Javascript
+; Information added by drupal.org packaging script on 2008-03-20
+version = "5.x-1.x-dev"
+project = "live"
+datestamp = "1206014768"
+
Index: live.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/live/live.module,v
retrieving revision 1.1.2.8
diff -u -p -r1.1.2.8 live.module
--- live.module 20 Mar 2008 05:41:55 -0000 1.1.2.8
+++ live.module 24 Oct 2008 11:19:24 -0000
@@ -2,10 +2,15 @@
// $Id: live.module,v 1.1.2.8 2008/03/20 05:41:55 heine Exp $
/**
+ * @file
+ * Allows live previews of comments and nodes.
+ */
+
+/**
* Implementation of hook_perm().
*/
function live_perm() {
- return array('use live comment preview');
+ return array('use live comment preview', 'use live node preview');
}
/**
@@ -23,20 +28,21 @@ function live_menu($may_cache) {
);
$items[] = array(
+ 'path' => 'live/node/preview',
+ 'callback' => 'live_node_preview',
+ 'access' => user_access('use live node preview'),
+ 'type' => MENU_CALLBACK,
+ );
+
+ $items[] = array(
'path' => 'admin/settings/live',
'title' => t('Live'),
'description' => t('Basic configuration for preview placements and effects.'),
'callback' => 'drupal_get_form',
- 'callback arguments' => array('live_comment_settings'),
+ 'callback arguments' => array('live_preview_settings'),
'access' => user_access('administer site configuration'),
);
- $items[] = array(
- 'path' => 'admin/settings/live/comment',
- 'title' => t('Comment settings'),
- 'callback' => 'drupal_get_form',
- 'callback arguments' => array('live_comment_settings'),
- );
}
drupal_add_css(drupal_get_path('module', 'live') .'/common.css');
@@ -46,7 +52,7 @@ function live_menu($may_cache) {
/**
* Live Comments settings page.
*/
-function live_comment_settings() {
+function live_preview_settings() {
$form['live_comment_preview'] = array(
'#type' => 'fieldset',
'#title' => t('Live Comment Preview settings'),
@@ -79,6 +85,38 @@ function live_comment_settings() {
'#description' => t('After how long (in milliseconds) should comment preview update on focus, keyup or blur event.'),
);
+ $form['live_node_preview'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Live Node Preview settings'),
+ '#collapsible' => TRUE,
+ '#collapsed' => FALSE,
+ );
+
+ $form['live_node_preview']['live_node_preview_element'] = array(
+ '#type' => 'textfield',
+ '#title' => t('CSS selector to attach node preview box to'),
+ '#default_value' => variable_get('live_node_preview_element', 'form#node-form'),
+ '#description' => t('A valid CSS selector to attach the node preview box to. Example: body, form#node-form, div.my-class'),
+ '#required' => TRUE,
+ );
+
+ $form['live_node_preview']['live_node_preview_element_method'] = array(
+ '#type' => 'radios',
+ '#title' => t('Attach method'),
+ '#options' => drupal_map_assoc(array('prepend', 'append', 'replace')),
+ '#default_value' => variable_get('live_node_preview_element_method', 'append'),
+ '#description' => t('Choose how the node preview box should be attached to the above selector.'),
+ '#required' => TRUE,
+ );
+
+ $form['live_node_preview']['live_node_preview_types_enabled'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Node types'),
+ '#description' => t('Select the node types you want to enable live previews for.'),
+ '#default_value' => variable_get('live_node_preview_types_enabled', array()),
+ '#options' => node_get_types('names'),
+ );
+
return system_settings_form($form);
}
@@ -86,9 +124,11 @@ function live_comment_settings() {
* Implementation of hook_form_alter().
*/
function live_form_alter($form_id, &$form) {
- $access = user_access('use live comment preview');
+ $access_preview_comment = user_access('use live comment preview');
+ $access_preview_node = user_access('use live node preview');
- if ($form_id == 'comment_form' && $form['#after_build'][0] != 'comment_form_add_preview' && $access) {
+ // Comment preview
+ if ($form_id == 'comment_form' && $form['#after_build'][0] != 'comment_form_add_preview' && $access_preview_comment) {
global $base_url;
@@ -110,6 +150,32 @@ function live_form_alter($form_id, &$for
drupal_add_js($path .'/comment/live-comment.js');
}
+
+ // Node preview
+ if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id
+ && in_array($form['type']['#value'], variable_get('live_node_preview_types_enabled', array()), TRUE) && user_access('use live node preview')) {
+
+ global $base_url;
+
+ $path = drupal_get_path('module', 'live');
+ $token = $form['#token'] ? $form['#token'] : ($form['type']['#value'] .'_node_form');
+
+ drupal_add_js(array(
+ 'live' => array(
+ 'node' => array(
+ 'node_type' => $form['type']['#value'],
+ 'base_url' => $base_url,
+ 'token_value' => $token,
+ 'module_path' => $path,
+ 'element' => variable_get('live_node_preview_element', 'form#node-form'),
+ 'placement' => variable_get('live_node_preview_element_method', 'append'),
+ ),
+ )
+ ), 'setting');
+
+ drupal_add_js($path .'/node/live-node.js');
+
+ }
}
/**
@@ -122,7 +188,7 @@ function live_comment_preview() {
$body = isset($_POST['body']) ? $_POST['body'] : '';
$access = user_access('use live comment preview');
$token = $_POST['token'] != "" ? $_POST['token'] : "";
- $skip_anonymous = $user->uid == 0 ? true : false;
+ $skip_anonymous = $user->uid == 0 ? TRUE : FALSE;
$token_value = isset($_POST['token_value']) ? $_POST['token_value'] : '';
$valid_token = drupal_valid_token($token, $token_value, $skip_anonymous);
@@ -143,7 +209,7 @@ function live_comment_preview() {
$comment->comment = check_markup($body, $format);
$comment->subject = $_POST['subject'] ? $_POST['subject'] : trim(truncate_utf8(decode_entities(strip_tags($comment->comment)), 29, TRUE));
- $comment->uid = isset($user->uid) ? $user->uid : null;
+ $comment->uid = isset($user->uid) ? $user->uid : NULL;
$comment->timestamp = time();
$output = '
'. t('Comment Preview') .'
';
@@ -152,3 +218,120 @@ function live_comment_preview() {
print $output;
}
+
+/**
+ * Construct and Output node preview securely.
+ */
+function live_node_preview() {
+ global $user;
+
+ $node->title = isset($_POST['title']) ? $_POST['title'] : '';
+ $node->format = isset($_POST['format']) ? $_POST['format'] : 1;
+ $node->body = isset($_POST['body']) ? check_markup($_POST['body'], $node->format) : '';
+ $node->type = isset($_POST['node_type']) ? $_POST['node_type'] : '';
+ $node->created = isset($_POST['date']) ? strtotime($_POST['date']) : time();
+ $node->changed = time();
+ $node->name = isset($_POST['username']) ? $_POST['username'] : t('Anonymous');
+
+ $access = user_access('use live node preview');
+ $token = $_POST['token'] != "" ? $_POST['token'] : "";
+ $skip_anonymous = $user->uid == 0 ? TRUE : FALSE;
+ $token_value = isset($_POST['token_value']) ? $_POST['token_value'] : '';
+ $valid_token = drupal_valid_token($token, $token_value, $skip_anonymous);
+
+ if (!filter_access($node->format) || $node->title == "" || !$access || !$valid_token) {
+ // SECURITY CHECK!
+ // Deny access:
+ // 1) If the current user is not allowed to use specified input format; or
+ // 2) If the node title is empty
+ // 3) If user does not have the permission.
+ drupal_access_denied();
+ return;
+ }
+
+ // Avoid debug information(devel.module) from being added to the preview.
+ $GLOBALS['devel_shutdown'] = FALSE;
+
+ // Validate node
+ // @FIXME this simply doesn't work yet
+ $errors = live_node_validate($node);
+ if ($errors != TRUE) {
+ $print = print_r($errors, true);
+ print $print;
+ }
+
+ // Load the user's name when needed.
+ if (isset($node->name)) {
+ // The use of isset() is mandatory in the context of user IDs, because
+ // user ID 0 denotes the anonymous user.
+ if ($user = user_load(array('name' => $node->name))) {
+ $node->uid = $user->uid;
+ $node->picture = $user->picture;
+ }
+ else {
+ $node->uid = 0; // anonymous user
+ }
+ }
+
+ // Display a preview of the node.
+ // Previewing alters $node so it needs to be cloned.
+ $cloned_node = drupal_clone($node);
+ $cloned_node->build_mode = NODE_BUILD_PREVIEW;
+ $cloned_node->in_preview = 1;
+
+ $output = theme('node_preview', $cloned_node);
+ print $output;
+}
+
+/**
+ * Validate the node
+ */
+function live_node_validate($node) {
+ // Convert the node to an object, if necessary.
+ $node = (object)$node;
+ $type = node_get_types('type', $node);
+ $errors = array();
+
+ if ($node->title == '') {
+ $errors[] = t('Title field is required.');
+ }
+
+ // Make sure the body has the minimum number of words.
+ // TODO : use a better word counting algorithm that will work in other languages
+ if (!empty($type->min_word_count) && isset($node->body) && count(explode(' ', $node->body)) < $type->min_word_count) {
+ //form_set_error('body', t('The body of your @type is too short. You need at least %words words.', array('%words' => $type->min_word_count, '@type' => $type->name)));
+ $errors[] = t('The body of your @type is too short. You need at least %words words.', array('%words' => $type->min_word_count, '@type' => $type->name));
+ }
+
+ if (isset($node->nid) && (node_last_changed($node->nid) > $node->changed)) {
+ //form_set_error('changed', t('This content has been modified by another user, changes cannot be saved.'));
+ $errors[] = t('This content has been modified by another user, changes cannot be saved.');
+ }
+
+ if (user_access('administer nodes')) {
+ // Validate the "authored by" field.
+ if (!empty($node->name) && !($account = user_load(array('name' => $node->name)))) {
+ // The use of empty() is mandatory in the context of usernames
+ // as the empty string denotes the anonymous user. In case we
+ // are dealing with an anonymous user we set the user ID to 0.
+ //form_set_error('name', t('The username %name does not exist.', array('%name' => $node->name)));
+ $errors[] = t('The username %name does not exist.', array('%name' => $node->name));
+ }
+
+ // Validate the "authored on" field. As of PHP 5.1.0, strtotime returns FALSE instead of -1 upon failure.
+ if (!empty($node->date) && strtotime($node->date) <= 0) {
+ //form_set_error('date', t('You have to specify a valid date.'));
+ $errors[] = t('You have to specify a valid date.');
+ }
+ }
+
+ // Do node-type-specific validation checks.
+ //node_invoke($node, 'validate', $form);
+ //node_invoke_nodeapi($node, 'validate', $form);
+
+ if (count($errors)) {
+ return $errors;
+ }
+
+ return true;
+}
--- /dev/null 2008-07-02 12:47:48.000000000 +0200
+++ node/live-node.js 2008-10-24 13:18:40.000000000 +0200
@@ -0,0 +1,79 @@
+// $Id$
+
+Drupal.liveNodePreview = function() {
+ var element = Drupal.settings.live.node.element;
+ var node_type = Drupal.settings.live.node.node_type;
+ var base_url = Drupal.settings.live.node.basePath + '/';
+ var module_path = Drupal.settings.live.node.module_path + '/';
+ var token_value = Drupal.settings.live.node.token_value;
+ $('#node-form input#edit-preview').one('click', function() {
+ var box = '
';
+ switch (Drupal.settings.live.node.placement) {
+ case 'prepend':
+ $(box).prependTo(element);
+ break;
+ case 'append':
+ $(box).appendTo(element);
+ break;
+ case 'replace':
+ $(element).html(box);
+ break;
+ default:
+ $(box).appendTo('form#node-form');
+ break;
+ }
+ }).bind('click', updateNodePreview);
+
+ function updateNodePreview() {
+ var preview_button = $(this);
+ var title = $('input#edit-title').val() || '';
+ var body = $('textarea#edit-body').val() || '';
+ var username = $('input#edit-name').val() || '';
+ var date = $('input#edit-date').val() || '';
+ var format = $('input[@name=format][@type=radio][@checked]').val() || 1;
+ var token = $('input[@name=form_token]#edit-'+ node_type +'-node-form-form-token').val() || "";
+
+ var node_div = $('div#live-node-preview');
+ var node_div_background = $('div#live-node-preview-background');
+ var progress_panel = $('
Loading...
');
+
+ jQuery.ajax({
+ type: "POST",
+ url: base_url + 'index.php?q=live/node/preview',
+ data: {
+ node_type: node_type,
+ title: title,
+ body: body,
+ username: username,
+ date: date,
+ format: format,
+ token: token,
+ token_value: token_value
+ },
+ timeout: 5000,
+ beforeSend: function() {
+ progress_panel.appendTo('body').hide().fadeIn(200);
+ },
+ success: function(data){
+ node_div.html(data);
+ $('div.live-progress-panel').remove();
+ preview_button.val('Update Preview');
+ },
+ error: function() {
+ progress_panel.html('Error requesting data!');
+ preview_button.val('Preview');
+ node_div.parent().slideUp();
+ setTimeout(function() {
+ progress_panel.fadeTo(1500, 0, function() {
+ $(this).remove();
+ });
+ }, 2500);
+ }
+ });
+ return false;
+ }
+}
+
+if (Drupal.jsEnabled) {
+ $(document).ready(Drupal.liveNodePreview);
+}