- Patch #107061 by Steven et al: add jQuery teaser splitter.
parent
15d739a504
commit
dcbb5fa3f4
|
@ -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.
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -170,6 +170,28 @@ function node_mark($nid, $timestamp) {
|
|||
return MARK_READ;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -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 "<!--break-->" (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 "<!--break-->" (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>';
|
||||
|
@ -2957,6 +2992,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().
|
||||
*/
|
||||
|
@ -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;
|
||||
|
|
|
@ -357,6 +357,31 @@ html.js .resizable-textarea textarea {
|
|||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue