Skip to content

Commit

Permalink
added AutoResizeTextarea
Browse files Browse the repository at this point in the history
  • Loading branch information
Carl Meyer committed Mar 5, 2010
1 parent 04e3c7f commit 5f0362d
Show file tree
Hide file tree
Showing 8 changed files with 256 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Expand Up @@ -4,6 +4,8 @@ CHANGES
tip (unreleased) tip (unreleased)
---------------- ----------------


- Added AutoResizeTextarea

0.1.7 (2009.12.02) 0.1.7 (2009.12.02)
------------------ ------------------


Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
Expand Up @@ -3,4 +3,6 @@ include CHANGES.rst
include LICENSE.txt include LICENSE.txt
include MANIFEST.in include MANIFEST.in
include README.rst include README.rst
include HGREV
recursive-include form_utils/templates *.html recursive-include form_utils/templates *.html
recursive-include form_utils/media/form_utils/js *.js
71 changes: 65 additions & 6 deletions README.rst
Expand Up @@ -20,6 +20,9 @@ This application provides utilities for enhancing Django's form handling:
3. An ``ImageWidget`` which display a thumbnail of the image 3. An ``ImageWidget`` which display a thumbnail of the image
rather than just the filename. rather than just the filename.


4. An ``AutoResizeTextarea`` widget which auto-resizes to
accomodate its contents.

Installation Installation
============ ============


Expand Down Expand Up @@ -53,13 +56,20 @@ Dependencies
`sorl-thumbnail`_ is optional, but without it full-size images will be `sorl-thumbnail`_ is optional, but without it full-size images will be
displayed instead of thumbnails. displayed instead of thumbnails.


`AutoResizeTextarea`_ requires `jQuery`_ (by default using a
Google-served version; see `JQUERY_URL`_).

.. _Django: http://www.djangoproject.com/ .. _Django: http://www.djangoproject.com/
.. _sorl-thumbnail: http://pypi.python.org/pypi/sorl-thumbnail .. _sorl-thumbnail: http://pypi.python.org/pypi/sorl-thumbnail
.. _Python Imaging Library: http://www.pythonware.com/products/pil/ .. _Python Imaging Library: http://www.pythonware.com/products/pil/
.. _jQuery: http://www.jquery.com/


Usage Usage
===== =====


BetterForm
----------

Simply inherit your form class from ``form_utils.forms.BetterForm`` (rather Simply inherit your form class from ``form_utils.forms.BetterForm`` (rather
than ``django.forms.Form``), or your modelform class from than ``django.forms.Form``), or your modelform class from
``form_utils.forms.BetterModelForm``, and define the ``fieldsets`` and/or ``form_utils.forms.BetterModelForm``, and define the ``fieldsets`` and/or
Expand All @@ -77,7 +87,7 @@ than ``django.forms.Form``), or your modelform class from
row_attrs = {'one': {'style': 'display: none'}} row_attrs = {'one': {'style': 'display: none'}}


fieldsets fieldsets
--------- '''''''''


Fieldset definitions are similar to ModelAdmin fieldset definitions: Fieldset definitions are similar to ModelAdmin fieldset definitions:
each fieldset is a two-tuple with a name and an options each fieldset is a two-tuple with a name and an options
Expand Down Expand Up @@ -113,7 +123,7 @@ regardless of fieldsets.
For more detailed examples, see the tests in ``tests/tests.py``. For more detailed examples, see the tests in ``tests/tests.py``.


row_attrs row_attrs
--------- '''''''''


The row_attrs declaration is a dictionary mapping field names to The row_attrs declaration is a dictionary mapping field names to
dictionaries of attribute/value pairs. The attribute/value dictionaries of attribute/value pairs. The attribute/value
Expand All @@ -127,7 +137,7 @@ added to the row_attrs of each ``BoundField``, depending on whether
the field is required. the field is required.


Rendering Rendering
--------- '''''''''


A possible template for rendering a ``BetterForm``:: A possible template for rendering a ``BetterForm``::


Expand Down Expand Up @@ -174,9 +184,6 @@ rendering the form::


{{ form|render:"my_form_stuff/custom_form_template.html" }} {{ form|render:"my_form_stuff/custom_form_template.html" }}


Fields and Widgets
==================

ClearableFileField ClearableFileField
------------------ ------------------


Expand Down Expand Up @@ -270,3 +277,55 @@ using ``formfield_overrides``::


.. _sorl-thumbnail: http://pypi.python.org/pypi/sorl-thumbnail .. _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``.

3 changes: 3 additions & 0 deletions form_utils/media/form_utils/js/autoresize.js
@@ -0,0 +1,3 @@
$(document).ready(function() {
$('textarea.autoresize').autogrow();
});
132 changes: 132 additions & 0 deletions form_utils/media/form_utils/js/jquery.autogrow.js
@@ -0,0 +1,132 @@
/*
* 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);
12 changes: 12 additions & 0 deletions form_utils/settings.py
@@ -0,0 +1,12 @@
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)
39 changes: 38 additions & 1 deletion form_utils/widgets.py
@@ -1,7 +1,7 @@
""" """
widgets for django-form-utils 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/ parts of this code taken from http://www.djangosnippets.org/snippets/934/
- thanks baumer1122 - thanks baumer1122
Expand All @@ -18,6 +18,8 @@
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile


from form_utils.settings import JQUERY_URL, FORM_UTILS_MEDIA_URL

try: try:
from sorl.thumbnail.main import DjangoThumbnail from sorl.thumbnail.main import DjangoThumbnail
def thumbnail(image_path): def thumbnail(image_path):
Expand Down Expand Up @@ -72,3 +74,38 @@ def format_output(self, rendered_widgets):
return self.template % {'input': rendered_widgets[0], return self.template % {'input': rendered_widgets[0],
'checkbox': rendered_widgets[1]} 'checkbox': rendered_widgets[1]}
return rendered_widgets[0] 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)

3 changes: 2 additions & 1 deletion setup.py
Expand Up @@ -41,6 +41,7 @@
'Framework :: Django', 'Framework :: Django',
], ],
zip_safe=False, 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' test_suite='tests.runtests.runtests'
) )

0 comments on commit 5f0362d

Please sign in to comment.