Commits

Anonymous committed 4d674e3

added AutoResizeTextarea

  • Participants
  • Parent commits 4890e74

Comments (0)

Files changed (8)

 tip (unreleased)
 ----------------
 
+- Added AutoResizeTextarea
+
 0.1.7 (2009.12.02)
 ------------------
 
 include LICENSE.txt
 include MANIFEST.in
 include README.rst
+include HGREV
 recursive-include form_utils/templates *.html
+recursive-include form_utils/media/form_utils/js *.js
     3. An ``ImageWidget`` which display a thumbnail of the image
        rather than just the filename.
 
+    4. An ``AutoResizeTextarea`` widget which auto-resizes to
+       accomodate its contents.
+
 Installation
 ============
 
 `sorl-thumbnail`_ is optional, but without it full-size images will be
 displayed instead of thumbnails.
 
+`AutoResizeTextarea`_ requires `jQuery`_ (by default using a
+Google-served version; see `JQUERY_URL`_).
+
 .. _Django: http://www.djangoproject.com/
 .. _sorl-thumbnail: http://pypi.python.org/pypi/sorl-thumbnail
 .. _Python Imaging Library: http://www.pythonware.com/products/pil/
+.. _jQuery: http://www.jquery.com/
 
 Usage
 =====
 
+BetterForm
+----------
+
 Simply inherit your form class from ``form_utils.forms.BetterForm`` (rather
 than ``django.forms.Form``), or your modelform class from
 ``form_utils.forms.BetterModelForm``, and define the ``fieldsets`` and/or
             row_attrs = {'one': {'style': 'display: none'}}
 
 fieldsets
----------
+'''''''''
 
 Fieldset definitions are similar to ModelAdmin fieldset definitions:
 each fieldset is a two-tuple with a name and an options
 For more detailed examples, see the tests in ``tests/tests.py``.
 
 row_attrs
----------
+'''''''''
 
 The row_attrs declaration is a dictionary mapping field names to
 dictionaries of attribute/value pairs.  The attribute/value
 the field is required.
 
 Rendering
----------
+'''''''''
 
 A possible template for rendering a ``BetterForm``::
 
 
     {{ form|render:"my_form_stuff/custom_form_template.html" }}
 
-Fields and Widgets
-==================
-
 ClearableFileField
 ------------------
 
 
 .. _sorl-thumbnail: http://pypi.python.org/pypi/sorl-thumbnail
 
+AutoResizeTextarea
+------------------
+
+Just import the widget and assign it to a form field::
+
+    from django import forms
+    from form_utils.widgets import AutoResizeTextarea
+    
+    class MyForm(forms.Form):
+        description = forms.CharField(widget=AutoResizeTextarea())
+
+Or use it in ``formfield_overrides`` in your ``ModelAdmin`` subclass::
+
+    from django import forms
+    from django.contrib import admin
+    from form_utils.widgets import AutoResizeTextarea
+    
+    class MyModelAdmin(admin.ModelAdmin):
+        formfield_overrides = {forms.CharField: {'widget': AutoResizeTextarea()}}
+
+There is also an ``InlineAutoResizeTextarea``, which simply provides
+smaller default sizes suitable for use in a tabular inline.
+
+Settings
+========
+
+FORM_UTILS_MEDIA_URL
+--------------------
+
+Some projects separate user-uploaded media at ``MEDIA_URL`` from
+static assets. If you keep static assets at a URL other than
+``MEDIA_URL``, just set ``FORM_UTILS_MEDIA_URL`` to that URL, and make
+sure the contents of the ``form_utils/media/form_utils`` directory are
+available at ``FORM_UTILS_MEDIA_URL/form_utils/``.
+
+
+JQUERY_URL
+----------
+
+`AutoResizeTextarea`_ requires the jQuery Javascript library.  By
+default, ``django-form-utils`` links to the most recent minor version
+of jQuery 1.4 available at ajax.googleapis.com (via the URL
+``http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js``).
+If you wish to use a different version of jQuery, or host it yourself,
+set the JQUERY_URL setting.  For example::
+
+    JQUERY_URL = 'jquery.min.js'
+
+This will use the jQuery available at MEDIA_URL/jquery.min.js. Note
+that a relative ``JQUERY_URL`` is always relative to ``MEDIA_URL``, it
+does not use ``FORM_UTILS_MEDIA_URL``.
+

form_utils/media/form_utils/js/autoresize.js

+$(document).ready(function() {
+	$('textarea.autoresize').autogrow();
+    });

form_utils/media/form_utils/js/jquery.autogrow.js

+/* 
+ * Auto Expanding Text Area (1.2.2)
+ * by Chrys Bader (www.chrysbader.com)
+ * chrysb@gmail.com
+ *
+ * Special thanks to:
+ * Jake Chapa - jake@hybridstudio.com
+ * John Resig - jeresig@gmail.com
+ *
+ * Copyright (c) 2008 Chrys Bader (www.chrysbader.com)
+ * Licensed under the GPL (GPL-LICENSE.txt) license. 
+ *
+ *
+ * NOTE: This script requires jQuery to work.  Download jQuery at www.jquery.com
+ *
+ */
+ 
+(function(jQuery) {
+		  
+	var self = null;
+ 
+	jQuery.fn.autogrow = function(o)
+	{	
+		return this.each(function() {
+			new jQuery.autogrow(this, o);
+		});
+	};
+	
+
+    /**
+     * The autogrow object.
+     *
+     * @constructor
+     * @name jQuery.autogrow
+     * @param Object e The textarea to create the autogrow for.
+     * @param Hash o A set of key/value pairs to set as configuration properties.
+     * @cat Plugins/autogrow
+     */
+	
+	jQuery.autogrow = function (e, o)
+	{
+		this.options		  	= o || {};
+		this.dummy			  	= null;
+		this.interval	 	  	= null;
+		this.line_height	  	= this.options.lineHeight || parseInt(jQuery(e).css('line-height'));
+		this.min_height		  	= this.options.minHeight || parseInt(jQuery(e).css('min-height'));
+		this.max_height		  	= this.options.maxHeight || parseInt(jQuery(e).css('max-height'));;
+		this.textarea		  	= jQuery(e);
+		
+		if(this.line_height == NaN)
+		  this.line_height = 0;
+		
+		// Only one textarea activated at a time, the one being used
+		this.init();
+	};
+	
+	jQuery.autogrow.fn = jQuery.autogrow.prototype = {
+    autogrow: '1.2.2'
+  };
+	
+ 	jQuery.autogrow.fn.extend = jQuery.autogrow.extend = jQuery.extend;
+	
+	jQuery.autogrow.fn.extend({
+						 
+		init: function() {			
+			var self = this;			
+			this.textarea.css({overflow: 'hidden', display: 'block'});
+			this.textarea.bind('focus', function() { self.startExpand() } ).bind('blur', function() { self.stopExpand() });
+			this.checkExpand();	
+		},
+						 
+		startExpand: function() {				
+		  var self = this;
+			this.interval = window.setInterval(function() {self.checkExpand()}, 400);
+		},
+		
+		stopExpand: function() {
+			clearInterval(this.interval);	
+		},
+		
+		checkExpand: function() {
+			
+			if (this.dummy == null)
+			{
+				this.dummy = jQuery('<div></div>');
+				this.dummy.css({
+												'font-size'  : this.textarea.css('font-size'),
+												'font-family': this.textarea.css('font-family'),
+												'width'      : this.textarea.css('width'),
+												'padding'    : this.textarea.css('padding'),
+												'line-height': this.line_height + 'px',
+												'overflow-x' : 'hidden',
+												'position'   : 'absolute',
+												'top'        : 0,
+												'left'		 : -9999
+												}).appendTo('body');
+			}
+			
+			// Strip HTML tags
+			var html = this.textarea.val().replace(/(<|>)/g, '');
+			
+			// IE is different, as per usual
+			if ($.browser.msie)
+			{
+				html = html.replace(/\n/g, '<BR>new');
+			}
+			else
+			{
+				html = html.replace(/\n/g, '<br>new');
+			}
+			
+			if (this.dummy.html() != html)
+			{
+				this.dummy.html(html);	
+				
+				if (this.max_height > 0 && (this.dummy.height() + this.line_height > this.max_height))
+				{
+					this.textarea.css('overflow-y', 'auto');	
+				}
+				else
+				{
+					this.textarea.css('overflow-y', 'hidden');
+					if (this.textarea.height() < this.dummy.height() + this.line_height || (this.dummy.height() < this.textarea.height()))
+					{	
+						this.textarea.animate({height: (this.dummy.height() + this.line_height) + 'px'}, 100);	
+					}
+				}
+			}
+		}
+						 
+	 });
+})(jQuery);

form_utils/settings.py

+import posixpath
+
+from django.conf import settings
+
+JQUERY_URL = getattr(
+    settings, 'JQUERY_URL',
+    'http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js')
+
+if not ((':' in JQUERY_URL) or (JQUERY_URL.startswith('/'))):
+    JQUERY_URL = posixpath.join(settings.MEDIA_URL, JQUERY_URL)
+
+FORM_UTILS_MEDIA_URL = getattr(settings, 'FORM_UTILS_MEDIA_URL', settings.MEDIA_URL)

form_utils/widgets.py

 """
 widgets for django-form-utils
 
-Time-stamp: <2009-11-25 02:54:50 carljm widgets.py>
+Time-stamp: <2010-03-05 15:03:36 carljm widgets.py>
 
 parts of this code taken from http://www.djangosnippets.org/snippets/934/
  - thanks baumer1122
 from django.utils.safestring import mark_safe
 from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile
 
+from form_utils.settings import JQUERY_URL, FORM_UTILS_MEDIA_URL
+
 try:
     from sorl.thumbnail.main import DjangoThumbnail
     def thumbnail(image_path):
             return self.template % {'input': rendered_widgets[0],
                                     'checkbox': rendered_widgets[1]}
         return rendered_widgets[0]
+
+root = lambda path: posixpath.join(FORM_UTILS_MEDIA_URL, path)
+    
+class AutoResizeTextarea(forms.Textarea):
+    """
+    A Textarea widget that automatically resizes to accomodate its contents.
+    
+    """
+    class Media:
+        
+        js = (JQUERY_URL,
+              root('form_utils/js/jquery.autogrow.js'),
+              root('form_utils/js/autoresize.js'))
+
+    def __init__(self, *args, **kwargs):
+        attrs = kwargs.setdefault('attrs', {})
+        try:
+            attrs['class'] = "%s autoresize" % (attrs['class'],)
+        except KeyError:
+            attrs['class'] = 'autoresize'
+        attrs.setdefault('cols', 80)
+        attrs.setdefault('rows', 5)
+        super(AutoResizeTextarea, self).__init__(*args, **kwargs)
+
+class InlineAutoResizeTextarea(AutoResizeTextarea):
+    def __init__(self, *args, **kwargs):
+        attrs = kwargs.setdefault('attrs', {})
+        try:
+            attrs['class'] = "%s inline" % (attrs['class'],)
+        except KeyError:
+            attrs['class'] = 'inline'
+        attrs.setdefault('cols', 40)
+        attrs.setdefault('rows', 2)
+        super(InlineAutoResizeTextarea, self).__init__(*args, **kwargs)
+
         'Framework :: Django',
     ],
     zip_safe=False,
-    package_data={'form_utils': ['templates/form_utils/*.html']},
+    package_data={'form_utils': ['templates/form_utils/*.html',
+                                 'media/form_utils/js/*.js']},
     test_suite='tests.runtests.runtests'
 )