summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2007-04-09 13:58:03 +0000
committerDries Buytaert <dries@buytaert.net>2007-04-09 13:58:03 +0000
commitdcbb5fa3f4434be266793f6a610071a14c777414 (patch)
tree10a5bae9c26e0fad6a5d08eadf6fd082304354d2
parent15d739a5049091821c81006ad8080f0556053e16 (diff)
downloadbrdo-dcbb5fa3f4434be266793f6a610071a14c777414.tar.gz
brdo-dcbb5fa3f4434be266793f6a610071a14c777414.tar.bz2
- Patch #107061 by Steven et al: add jQuery teaser splitter.
-rw-r--r--CHANGELOG.txt1
-rw-r--r--includes/form.inc12
-rw-r--r--misc/drupal.js20
-rw-r--r--misc/teaser.js80
-rw-r--r--misc/textarea.js6
-rw-r--r--modules/block/block.module6
-rw-r--r--modules/blog/blog.module3
-rw-r--r--modules/book/book.module9
-rw-r--r--modules/forum/forum.module3
-rw-r--r--modules/node/node.module84
-rw-r--r--modules/system/system.css25
11 files changed, 226 insertions, 23 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 2d4fe6bdb..45c10ae96 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -8,6 +8,7 @@ Drupal 6.0, xxxx-xx-xx (development version)
- Drupal works with error reporting set to E_ALL.
- Added scripts/drupal.sh to execute Drupal code from the command line. Useful to use Drupal as a framework to build command-line tools.
- Used the Garland theme for the installation and maintenance pages.
+- Improved handling of teasers in posts.
- Added generic language management functionality.
* Support for right to left scripts.
* Language detection based on parts of the URL.
diff --git a/includes/form.inc b/includes/form.inc
index 0ce8b3d3a..1845f4d9a 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -1452,6 +1452,18 @@ function theme_form($element) {
*/
function theme_textarea($element) {
$class = array('form-textarea');
+
+ // Add teaser behaviour (must come before resizable)
+ if (!empty($element['#teaser'])) {
+ drupal_add_js('misc/teaser.js');
+ // Note: arrays are merged in drupal_get_js().
+ drupal_add_js(array('teaserButton' => array(t('Join summary'), t('Split summary at cursor'))), 'setting');
+ drupal_add_js(array('teaserCheckbox' => array($element['#id'] => $element['#teaser_checkbox'])), 'setting');
+ drupal_add_js(array('teaser' => array($element['#id'] => $element['#teaser'])), 'setting');
+ $class[] = 'teaser';
+ }
+
+ // Add resizable behaviour
if ($element['#resizable'] !== FALSE) {
drupal_add_js('misc/textarea.js');
$class[] = 'resizable';
diff --git a/misc/drupal.js b/misc/drupal.js
index b4130e4ad..04176089d 100644
--- a/misc/drupal.js
+++ b/misc/drupal.js
@@ -200,6 +200,26 @@ Drupal.encodeURIComponent = function (item, uri) {
return uri.indexOf('?q=') ? item : item.replace('%26', '%2526').replace('%23', '%2523');
};
+/**
+ * Get the text selection in a textarea.
+ */
+Drupal.getSelection = function (element) {
+ if (typeof(element.selectionStart) != 'number' && document.selection) {
+ // The current selection
+ var range1 = document.selection.createRange();
+ var range2 = range1.duplicate();
+ // Select all text.
+ range2.moveToElementText(element);
+ // Now move 'dummy' end point to end point of original range.
+ range2.setEndPoint('EndToEnd', range1);
+ // Now we can calculate start and end points.
+ var start = range2.text.length - range1.text.length;
+ var end = start + range1.text.length;
+ return { 'start': start, 'end': end };
+ }
+ return { 'start': element.selectionStart, 'end': element.selectionEnd };
+}
+
// Global Killswitch on the <html> element
if (Drupal.jsEnabled) {
document.documentElement.className = 'js';
diff --git a/misc/teaser.js b/misc/teaser.js
new file mode 100644
index 000000000..12275fc39
--- /dev/null
+++ b/misc/teaser.js
@@ -0,0 +1,80 @@
+// $Id$
+
+/**
+ * Auto-attach for teaser behaviour.
+ *
+ * Note: depends on resizable textareas.
+ */
+Drupal.teaserAttach = function() {
+ $('textarea.teaser:not(.joined)').each(function() {
+ var teaser = $(this).addClass('joined');
+
+ // Move teaser textarea before body, and remove its form-item wrapper.
+ var body = $('#'+ Drupal.settings.teaser[this.id]);
+ var checkbox = $('#'+ Drupal.settings.teaserCheckbox[this.id]).parent();
+ var parent = teaser[0].parentNode;
+ $(body).before(teaser);
+ $(parent).remove();
+
+ function trim(text) {
+ return text.replace(/^\s+/g, '').replace(/\s+$/g, '');
+ }
+
+ // Join the teaser back to the body.
+ function join_teaser() {
+ if (teaser.val()) {
+ body.val(trim(teaser.val()) +'\r\n\r\n'+ trim(body.val()));
+ }
+ // Hide and disable teaser
+ $(teaser).attr('disabled', 'disabled');
+ $(teaser).parent().slideUp('fast');
+ // Change label
+ $(this).val(Drupal.settings.teaserButton[1]);
+ // Show separate teaser checkbox
+ $(checkbox).hide();
+ }
+
+ // Split the teaser from the body.
+ function split_teaser() {
+ body[0].focus();
+ var selection = Drupal.getSelection(body[0]);
+ var split = selection.start;
+ var text = body.val();
+
+ // Note: using val() fails sometimes. jQuery bug?
+ teaser[0].value = trim(text.slice(0, split));
+ body[0].value = trim(text.slice(split));
+ // Reveal and enable teaser
+ $(teaser).attr('disabled', '');
+ $(teaser).parent().slideDown('fast');
+ // Change label
+ $(this).val(Drupal.settings.teaserButton[0]);
+ // Show separate teaser checkbox
+ $(checkbox).show();
+ }
+
+ // Add split/join button.
+ var button = $('<div class="teaser-button-wrapper"><input type="button" class="teaser-button" /></div>');
+ var include = $('#'+ this.id.substring(0, this.id.length - 2) +'include');
+ $(include).parent().parent().before(button);
+
+ // Extract the teaser from the body, if set. Otherwise, stay in joined mode.
+ var text = body.val().split('<!--break-->', 2);
+ if (text.length == 2) {
+ teaser[0].value = trim(text[0]);
+ body[0].value = trim(text[1]);
+ $(teaser).attr('disabled', '');
+ $('input', button).val(Drupal.settings.teaserButton[0]).toggle(join_teaser, split_teaser);
+ }
+ else {
+ $(teaser).hide();
+ $('input', button).val(Drupal.settings.teaserButton[1]).toggle(split_teaser, join_teaser);
+ $(checkbox).hide();
+ }
+
+ });
+}
+
+if (Drupal.jsEnabled) {
+ $(document).ready(Drupal.teaserAttach);
+}
diff --git a/misc/textarea.js b/misc/textarea.js
index 6fe92234d..34217c7e5 100644
--- a/misc/textarea.js
+++ b/misc/textarea.js
@@ -7,6 +7,12 @@ Drupal.textareaAttach = function() {
$(this).wrap('<div class="resizable-textarea"></div>')
.parent().append($('<div class="grippie"></div>').mousedown(startDrag));
+ // Inherit visibility
+ if ($(this).is(':hidden')) {
+ $(this).parent().hide();
+ $(this).show();
+ }
+
var grippie = $('div.grippie', $(this).parent())[0];
grippie.style.marginRight = (grippie.offsetWidth - $(this)[0].offsetWidth) +'px';
diff --git a/modules/block/block.module b/modules/block/block.module
index 916a8dc6d..a61f21f35 100644
--- a/modules/block/block.module
+++ b/modules/block/block.module
@@ -595,8 +595,8 @@ function block_box_form($edit = array()) {
'#required' => TRUE,
'#weight' => -19,
);
- $form['body_filter']['#weight'] = -17;
- $form['body_filter']['body'] = array(
+ $form['body_field']['#weight'] = -17;
+ $form['body_field']['body'] = array(
'#type' => 'textarea',
'#title' => t('Block body'),
'#default_value' => $edit['body'],
@@ -607,7 +607,7 @@ function block_box_form($edit = array()) {
if (!isset($edit['format'])) {
$edit['format'] = FILTER_FORMAT_DEFAULT;
}
- $form['body_filter']['format'] = filter_form($edit['format'], -16);
+ $form['body_field']['format'] = filter_form($edit['format'], -16);
return $form;
}
diff --git a/modules/blog/blog.module b/modules/blog/blog.module
index 4c9fa1d88..ff61ba998 100644
--- a/modules/blog/blog.module
+++ b/modules/blog/blog.module
@@ -211,8 +211,7 @@ function blog_form(&$node) {
}
$form['title'] = array('#type' => 'textfield', '#title' => check_plain($type->title_label), '#required' => TRUE, '#default_value' => !empty($node->title) ? $node->title : NULL, '#weight' => -5);
- $form['body_filter']['body'] = array('#type' => 'textarea', '#title' => check_plain($type->body_label), '#default_value' => !empty($node->body) ? $node->title : NULL, '#rows' => 20, '#required' => TRUE);
- $form['body_filter']['filter'] = filter_form($node->format);
+ $form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
return $form;
}
diff --git a/modules/book/book.module b/modules/book/book.module
index 5437ee5a9..2c4a4f31f 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -232,13 +232,8 @@ function book_form(&$node) {
'#default_value' => $node->title,
'#weight' => -5,
);
- $form['body_filter']['body'] = array('#type' => 'textarea',
- '#title' => check_plain($type->body_label),
- '#default_value' => $node->body,
- '#rows' => 20,
- '#required' => TRUE,
- );
- $form['body_filter']['format'] = filter_form($node->format);
+
+ $form['body_field'] = node_body_field($node, $type->body_label, 1);
if (user_access('administer nodes')) {
$form['weight'] = array('#type' => 'weight',
diff --git a/modules/forum/forum.module b/modules/forum/forum.module
index 10d69901a..b5895d40f 100644
--- a/modules/forum/forum.module
+++ b/modules/forum/forum.module
@@ -423,8 +423,7 @@ function forum_form(&$node) {
$form['shadow'] = array('#type' => 'checkbox', '#title' => t('Leave shadow copy'), '#default_value' => $shadow, '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'));
}
- $form['body_filter']['body'] = array('#type' => 'textarea', '#title' => check_plain($type->body_label), '#default_value' => !empty($node->body) ? $node->body : '', '#rows' => 20, '#required' => TRUE);
- $form['body_filter']['format'] = filter_form($node->format);
+ $form['body_field'] = node_body_field($node, $type->body_label, 1);
return $form;
}
diff --git a/modules/node/node.module b/modules/node/node.module
index 92443f605..c79aeeea0 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -171,6 +171,28 @@ function node_mark($nid, $timestamp) {
}
/**
+ * See if the user used JS to submit a teaser.
+ */
+function node_teaser_js(&$form, $form_values) {
+ // Glue the teaser to the body.
+ if (isset($form['#post']['teaser_js'])) {
+ if (trim($form_values['teaser_js'])) {
+ // Space the teaser from the body
+ $body = trim($form_values['teaser_js']) ."\r\n<!--break-->\r\n". trim($form_values['body']);
+ }
+ else {
+ // Empty teaser, no spaces.
+ $body = '<!--break-->'. $form_values['body'];
+ }
+ // Pass value onto preview/submit
+ form_set_value($form['body'], $body);
+ // Pass value back onto form
+ $form['body']['#value'] = $body;
+ }
+ return $form;
+}
+
+/**
* Automatically generate a teaser for a node body in a given format.
*/
function node_teaser($body, $format = NULL) {
@@ -1876,7 +1898,16 @@ function node_submit($node) {
// Auto-generate the teaser, but only if it hasn't been set (e.g. by a
// module-provided 'teaser' form item).
if (!isset($node->teaser)) {
- $node->teaser = isset($node->body) ? node_teaser($node->body, isset($node->format) ? $node->format : NULL) : '';
+ if (isset($node->body)) {
+ $node->teaser = node_teaser($node->body, isset($node->format) ? $node->format : NULL);
+ // Chop off the teaser from the body if needed.
+ if (!$node->teaser_include && $node->teaser == substr($node->body, 0, strlen($node->teaser))) {
+ $node->body = substr($node->body, strlen($node->teaser));
+ }
+ }
+ else {
+ $node->teaser = '';
+ }
}
if (user_access('administer nodes')) {
@@ -2216,6 +2247,10 @@ function node_preview($node) {
// 'teaser' form item).
if (!isset($node->teaser)) {
$node->teaser = empty($node->body) ? '' : node_teaser($node->body, $node->format);
+ // Chop off the teaser from the body if needed.
+ if (!$node->teaser_include && $node->teaser == substr($node->body, 0, strlen($node->teaser))) {
+ $node->body = substr($node->body, strlen($node->teaser));
+ }
}
// Display a preview of the node:
@@ -2241,7 +2276,7 @@ function node_preview($node) {
function theme_node_preview($node) {
$output = '<div class="preview">';
if ($node->teaser && $node->teaser != $node->body) {
- drupal_set_message(t('The trimmed version of your post shows what your post looks like when promoted to the main page or when exported for syndication. You can insert the delimiter "&lt;!--break--&gt;" (without the quotes) to fine-tune where your post gets split.'));
+ drupal_set_message(t('The trimmed version of your post shows what your post looks like when promoted to the main page or when exported for syndication.<span class="no-js"> You can insert the delimiter "&lt;!--break--&gt;" (without the quotes) to fine-tune where your post gets split.</span>'));
$output .= '<h3>'. t('Preview trimmed version') .'</h3>';
$output .= node_view(drupal_clone($node), 1, FALSE, 0);
$output .= '<h3>'. t('Preview full version') .'</h3>';
@@ -2958,6 +2993,43 @@ function node_content_access($op, $node) {
}
/**
+ * Return a node body field, with format and teaser.
+ */
+function node_body_field(&$node, $label, $word_count) {
+
+ // 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)));
+
+ $form = array(
+ '#after_build' => array('node_teaser_js'));
+
+ $form['teaser_js'] = array(
+ '#type' => 'textarea',
+ '#rows' => 10,
+ '#teaser' => 'edit-body',
+ '#teaser_checkbox' => 'edit-teaser-include',
+ '#disabled' => TRUE);
+
+ $form['teaser_include'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Show summary in full view'),
+ '#default_value' => $include,
+ '#prefix' => '<div class="teaser-checkbox">',
+ '#suffix' => '</div>',
+ );
+
+ $form['body'] = array(
+ '#type' => 'textarea',
+ '#title' => check_plain($label),
+ '#default_value' => $include ? $node->body : ($node->teaser . $node->body),
+ '#rows' => 20,
+ '#required' => ($word_count > 0));
+
+ $form['format'] = filter_form($node->format);
+
+ return $form;
+}
+/**
* Implementation of hook_form().
*/
function node_content_form($node) {
@@ -2975,13 +3047,7 @@ function node_content_form($node) {
}
if ($type->has_body) {
- $form['body_filter']['body'] = array(
- '#type' => 'textarea',
- '#title' => check_plain($type->body_label),
- '#default_value' => $node->body,
- '#rows' => 20,
- '#required' => ($type->min_word_count > 0));
- $form['body_filter']['format'] = filter_form($node->format);
+ $form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
}
return $form;
diff --git a/modules/system/system.css b/modules/system/system.css
index c78d52127..fa03200e3 100644
--- a/modules/system/system.css
+++ b/modules/system/system.css
@@ -358,6 +358,31 @@ html.js .resizable-textarea textarea {
}
/*
+** Teaser splitter
+*/
+.joined + .grippie {
+ height: 5px;
+ background-position: center 1px;
+ margin-bottom: -2px;
+}
+div.teaser-button-wrapper {
+ float: right;
+ padding-right: 5%;
+ margin: 0;
+}
+.teaser-checkbox div.form-item {
+ float: right;
+ margin: 0 5% 0 0;
+ padding: 0;
+}
+textarea.teaser {
+ display: none;
+}
+html.js .no-js {
+ display: none;
+}
+
+/*
** Progressbar styles
*/
.progress {