Index: misc/collapse.js =================================================================== RCS file: /cvs/drupal/drupal/misc/collapse.js,v retrieving revision 1.16 diff -u -p -r1.16 collapse.js --- misc/collapse.js 12 Sep 2007 18:29:32 -0000 1.16 +++ misc/collapse.js 30 Oct 2007 09:57:21 -0000 @@ -12,12 +12,12 @@ Drupal.toggleFieldset = function(fieldse duration: 'fast', easing: 'linear', complete: function() { - Drupal.collapseScrollIntoView(this.parentNode); + Drupal.ScrollIntoView(this.parentNode); this.parentNode.animating = false; }, step: function() { // Scroll the fieldset into view - Drupal.collapseScrollIntoView(this.parentNode); + Drupal.ScrollIntoView(this.parentNode); } }); } @@ -29,23 +29,6 @@ Drupal.toggleFieldset = function(fieldse } }; -/** - * Scroll a given fieldset into view as much as possible. - */ -Drupal.collapseScrollIntoView = function (node) { - var h = self.innerHeight || document.documentElement.clientHeight || $('body')[0].clientHeight || 0; - var offset = self.pageYOffset || document.documentElement.scrollTop || $('body')[0].scrollTop || 0; - var posY = $(node).offset().top; - var fudge = 55; - if (posY + node.offsetHeight + fudge > h + offset) { - if (node.offsetHeight > h) { - window.scrollTo(0, posY); - } else { - window.scrollTo(0, posY + node.offsetHeight - h + fudge); - } - } -}; - Drupal.behaviors.collapse = function (context) { $('fieldset.collapsible > legend:not(.collapse-processed)', context).each(function() { var fieldset = $(this.parentNode); Index: misc/drupal.js =================================================================== RCS file: /cvs/drupal/drupal/misc/drupal.js,v retrieving revision 1.40 diff -u -p -r1.40 drupal.js --- misc/drupal.js 5 Oct 2007 09:35:08 -0000 1.40 +++ misc/drupal.js 30 Oct 2007 13:41:12 -0000 @@ -227,6 +227,39 @@ Drupal.encodeURIComponent = function (it }; /** + * Equivalent of check_plain(). + */ +Drupal.checkPlain = function (text) { + var entities = { + '&':'&', + '<':'<', + '>':'>', + '"':'"' + }; + for (i in entities) { + text = text.replace(new RegExp(i, 'g'), entities[i]); + } + return text; +} + +/** + * Scroll a given fieldset into view as much as possible. + */ +Drupal.ScrollIntoView = function (node) { + var h = self.innerHeight || document.documentElement.clientHeight || $('body')[0].clientHeight || 0; + var offset = self.pageYOffset || document.documentElement.scrollTop || $('body')[0].scrollTop || 0; + var posY = $(node).offset().top; + var fudge = 55; + if (posY + node.offsetHeight + fudge > h + offset) { + if (node.offsetHeight > h) { + window.scrollTo(0, posY - 20); + } else { + window.scrollTo(0, posY - 20 + node.offsetHeight - h + fudge); + } + } +}; + +/** * Get the text selection in a textarea. */ Drupal.getSelection = function (element) { Index: misc/textarea.js =================================================================== RCS file: /cvs/drupal/drupal/misc/textarea.js,v retrieving revision 1.18 diff -u -p -r1.18 textarea.js --- misc/textarea.js 12 Sep 2007 18:29:32 -0000 1.18 +++ misc/textarea.js 30 Oct 2007 14:56:01 -0000 @@ -1,9 +1,16 @@ // $Id: textarea.js,v 1.18 2007/09/12 18:29:32 goba Exp $ Drupal.behaviors.textarea = function(context) { + var i = 0; + // Attach to all unprocessed textareas. $('textarea.resizable:not(.textarea-processed)', context).each(function() { var textarea = $(this).addClass('textarea-processed'), staticOffset = null; + // We use a helper div to measure text. We wrap it an overflow: hidden + // container to avoid lengthening the page scrollbar. + $('body').append('
'); + var $helper = $('#expanderHelper'+ i); + // When wrapping the text area, work around an IE margin bug. See: // http://jaspan.com/ie-inherited-margin-bug-form-elements-and-haslayout $(this).wrap('
') @@ -18,22 +25,108 @@ Drupal.behaviors.textarea = function(con var grippie = $('div.grippie', $(this).parent())[0]; grippie.style.marginRight = (grippie.offsetWidth - $(this)[0].offsetWidth) +'px'; + // How far to shrink back. + var shrink = textarea.height(); + + // Clicking down on the grippie. function startDrag(e) { staticOffset = textarea.height() - e.pageY; textarea.css('opacity', 0.25); $(document).mousemove(performDrag).mouseup(endDrag); + shrink = textarea.height(); return false; } + // Moving the mouse during a drag. function performDrag(e) { textarea.height(Math.max(32, staticOffset + e.pageY) + 'px'); return false; } + var resized = false; + // Letting go of the button during drag. function endDrag(e) { $(document).unbind("mousemove"); $(document).unbind("mouseup"); textarea.css('opacity', 1); + resized = true; + } + + // Get text styles and apply them to the helper. + var style = { + fontFamily: $(this).css('fontFamily')||'', + fontSize: $(this).css('fontSize')||'', + fontWeight: $(this).css('fontWeight')||'', + fontStyle: $(this).css('fontStyle')||'', + fontStretch: $(this).css('fontStretch')||'', + fontVariant: $(this).css('fontVariant')||'', + letterSpacing: $(this).css('letterSpacing')||'', + wordSpacing: $(this).css('wordSpacing')||'', + lineHeight: $(this).css('lineHeight')||'', + textWrap: 'unrestricted' + }; + $helper.css(style); + + // Measure the text and some extra padding. + $helper.html('DruPal'); + var spacer = $helper[0].offsetWidth; + + // Add auto-expand event handler and fire it once. + $(this).blur(expand).keyup(expand).keypress(expand); + expand.apply(this); + + var last = this.value; + var time = (new Date()).getTime(); + // Auto-expand a textarea. + function expand() { + var e = this; + + // Don't expand if textarea has been resized. + if (resized) { + return; + } + + // Don't expand more than once every 250ms. + var now = (new Date()).getTime(); + if (now - time < 250) { + return; + } + time = now; + + // Force a tiny delay to ensure we get the entire value including the + // change this event causes. + window.setTimeout(function () { + // Don't expand if textarea is unchanged. + if (last == e.value) { + return; + } + // Get contents. + var text = (last = e.value); + + // Don't expand for extremely large textareas where we are sure to be + // at full size already. + if (e.value.length > 10000) { + return; + } + + // Convert text to HTML and size helper. + var html = Drupal.checkPlain(text); + if (!$.browser.safari && html.substring(html.length - 1) == "\n") { + html += 'x'; + } + html = html.replace(new RegExp("\\n", "g"), "
"); + $helper.css('width', ($(e).width() - ($.browser.safari && 12 || 2)) + 'px').html(html); + + // Calculate page height, minus some padding. + var limit = (self.innerHeight || document.documentElement.clientHeight || $('body')[0].clientHeight) - 85; + // Calculate desired height. + var height = Math.min(limit, $helper[0].offsetHeight + spacer); + height = Math.max(shrink, height); + + // Expand and scroll into view. + $(e).height(height); + Drupal.ScrollIntoView(e.parentNode.parentNode); + }, 1); } }); }; Index: modules/node/node.pages.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.pages.inc,v retrieving revision 1.6 diff -u -p -r1.6 node.pages.inc --- modules/node/node.pages.inc 22 Oct 2007 10:37:14 -0000 1.6 +++ modules/node/node.pages.inc 30 Oct 2007 11:06:25 -0000 @@ -247,7 +247,7 @@ function node_body_field(&$node, $label, '#type' => 'textarea', '#title' => check_plain($label), '#default_value' => $include ? $node->body : ($node->teaser . $node->body), - '#rows' => 20, + '#rows' => 8, '#required' => ($word_count > 0)); $form['format'] = filter_form($node->format);