From 5e49dd2a68aaa18db498b6b139e76c19f5c32fda Mon Sep 17 00:00:00 2001 From: Steven Wittens <steven@10.no-reply.drupal.org> Date: Thu, 29 Dec 2005 03:59:30 +0000 Subject: [PATCH] - #42446: Resizable textareas. --- includes/form.inc | 8 +++- misc/drupal.css | 14 +++++++ misc/drupal.js | 18 ++++++++ misc/textarea.js | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 misc/textarea.js diff --git a/includes/form.inc b/includes/form.inc index f6043cb1bbbe..4121d961d149 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -760,9 +760,15 @@ function theme_form($element) { * A themed HTML string representing the textarea. */ function theme_textarea($element) { + $class = 'textarea'; + if ($element['#resizable'] !== false) { + drupal_add_js('misc/textarea.js'); + $class .= ' resizable'; + } + $cols = $element['#cols'] ? ' cols="'. $element['#cols'] .'"' : ''; - return theme('form_element', $element['#title'], '<textarea'. $cols .' rows="'. $element['#rows'] .'" name="'. $element['#name'] .'" id="' . $element['#id'] .'" class="'. _form_get_class('textarea', $element['#required'], form_get_error($element)) .'"'. drupal_attributes($element['#attributes']) .'>'. check_plain($element['#value']) .'</textarea>', $element['#description'], $element['#id'], $element['#required'], form_get_error($element)); + return theme('form_element', $element['#title'], '<textarea'. $cols .' rows="'. $element['#rows'] .'" name="'. $element['#name'] .'" id="' . $element['#id'] .'" class="'. _form_get_class($class, $element['#required'], form_get_error($element)) .'"'. drupal_attributes($element['#attributes']) .'>'. check_plain($element['#value']) .'</textarea>', $element['#description'], $element['#id'], $element['#required'], form_get_error($element)); } /** diff --git a/misc/drupal.css b/misc/drupal.css index 18c37bfd16da..63813ddab35c 100644 --- a/misc/drupal.css +++ b/misc/drupal.css @@ -618,3 +618,17 @@ html.js fieldset.collapsed legend a { * html.js fieldset.collapsible legend a { display: block; } + +/* +** Resizable text areas +*/ +.resizable-textarea { + width: 95%; +} +.resizable-textarea .grippie { + height: 14px; + background: #eee url('grippie.png') no-repeat 100% 100%; + border: 1px solid #ddd; + border-top-width: 0px; + cursor: ns-resize; +} diff --git a/misc/drupal.js b/misc/drupal.js index e64d3bc6010c..c19dc565a45d 100644 --- a/misc/drupal.js +++ b/misc/drupal.js @@ -211,6 +211,10 @@ function absolutePosition(el) { return r; }; +function dimensions(el) { + return { width: el.offsetWidth, height: el.offsetHeight }; +} + /** * Returns true if an element has a specified class name */ @@ -279,6 +283,20 @@ function removeNode(node) { } } +/** + * Prevents an event from propagating. + */ +function stopEvent(event) { + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } + else { + event.returnValue = false; + event.cancelBubble = true; + } +} + /** * Wrapper around document.getElementById(). */ diff --git a/misc/textarea.js b/misc/textarea.js new file mode 100644 index 000000000000..32efb330539e --- /dev/null +++ b/misc/textarea.js @@ -0,0 +1,105 @@ +if (isJsEnabled()) { + addLoadEvent(function() { + // Attach to all textareas + textareas = document.getElementsByTagName('textarea'); + var textarea; + for (var i = 0; textarea = textareas[i]; ++i) { + if (hasClass(textarea, 'resizable')) { + new textArea(textarea); + } + } + }); +} + +function textArea(element) { + var ta = this; + this.element = element; + this.parent = this.element.parentNode; + this.dimensions = dimensions(element); + + // Prepare wrapper + this.wrapper = document.createElement('div'); + this.wrapper.className = 'resizable-textarea'; + this.parent.insertBefore(this.wrapper, this.element); + + // Add grippie and measure it + this.grippie = document.createElement('div'); + this.grippie.className = 'grippie'; + this.wrapper.appendChild(this.grippie); + this.grippie.dimensions = dimensions(this.grippie); + this.grippie.onmousedown = function (e) { ta.beginDrag(e); }; + this.element.onmouseup = function (e) { ta.endDrag(e); }; + + // Set wrapper and textarea dimensions + this.wrapper.style.height = this.dimensions.height + this.grippie.dimensions.height + 1 +'px'; + this.element.style.marginBottom = '0px'; + this.element.style.width = '100%'; + this.element.style.height = this.dimensions.height +'px'; + + // Wrap textarea + removeNode(this.element); + this.wrapper.insertBefore(this.element, this.grippie); + + // Measure difference between desired and actual textarea dimensions to account for padding/borders + this.widthOffset = dimensions(this.wrapper).width - this.dimensions.width; + + // Make the grippie line up in various browsers + if (window.opera) { + // Opera + this.grippie.style.marginRight = this.widthOffset +'px'; + } + if (document.all && !window.opera) { + // IE + this.grippie.style.width = '100%'; + this.grippie.style.paddingLeft = '2px'; + } + // Mozilla + this.element.style.MozBoxSizing = 'border-box'; + + this.heightOffset = absolutePosition(this.grippie).y - absolutePosition(this.element).y - this.dimensions.height; +} + +textArea.prototype.beginDrag = function (event) { + event = event || window.event; + // Capture mouse + var cp = this; + this.oldMoveHandler = document.onmousemove; + document.onmousemove = function(e) { cp.handleDrag(e); }; + this.oldUpHandler = document.onmouseup; + document.onmouseup = function(e) { cp.endDrag(e); }; + + // Store drag offset from grippie top + var pos = absolutePosition(this.grippie); + this.dragOffset = event.clientY - pos.y; + + // Make transparent + this.element.style.opacity = 0.5; + + // Process + this.handleDrag(event); +} + +textArea.prototype.handleDrag = function (event) { + event = event || window.event; + // Get coordinates relative to text area + var pos = absolutePosition(this.element); + var y = event.clientY - pos.y; + + // Set new height + var height = Math.max(32, y - this.dragOffset - this.heightOffset); + this.wrapper.style.height = height + this.grippie.dimensions.height + 1 + 'px'; + this.element.style.height = height + 'px'; + + // Avoid text selection + stopEvent(event); +} + +textArea.prototype.endDrag = function (event) { + // Uncapture mouse + document.onmousemove = this.oldMoveHandler; + document.onmouseup = this.oldUpHandler; + + // Restore opacity + this.element.style.opacity = 1.0; +} + -- GitLab