Mark Lavin avatar Mark Lavin committed cdc09bd Merge

Merge the latest work into stable.

Comments (0)

Files changed (67)

-Primary author: 
+Primary author:
 
 Mark Lavin
 
 The following people who have contributed to django-selectable:
 
+Michael Manfre
+Luke Plant
+Augusto Men
 @dc
 Colin Copeland
 Sławomir Ehlert
 David Ray
 Rick Testore
 Karen Tracey
+Manuel Alvarez
 
 Thanks for all of your work!
-Copyright (c) 2010-2012, Mark Lavin
+Copyright (c) 2010-2013, Mark Lavin
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
     Begining with version django-selectable version 0.6, Django 1.2 is no longer supported.
     While it may continue to work, bugs related to Django 1.2 support will not be fixed.
 
+    Version 0.7 adds experimental support for Python 3.2+ when used with Django 1.5+.
+
 To install::
-    
+
     pip install django-selectable
 
 Next add `selectable` to your `INSTALLED_APPS` to include the related css/js::
 
 Django-Selectables will work in the admin. To get started on integrated the
 fields and widgets in the admin make sure you are familiar with the Django
-documentation on the `ModelAdmin.form <http://docs.djangoproject.com/en/1.3/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form>`_ 
+documentation on the `ModelAdmin.form <http://docs.djangoproject.com/en/1.3/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form>`_
 and `ModelForms <http://docs.djangoproject.com/en/1.3/topics/forms/modelforms/>`_ particularly
-on `overriding the default widgets <http://docs.djangoproject.com/en/1.3/topics/forms/modelforms/#overriding-the-default-field-types-or-widgets>`_. 
+on `overriding the default widgets <http://docs.djangoproject.com/en/1.3/topics/forms/modelforms/#overriding-the-default-field-types-or-widgets>`_.
 As you will see integrating django-selectable in the adminis the same as working with regular forms.
 
+
 .. _admin-jquery-include:
 
 Including jQuery & jQuery UI
 --------------------------------------
 
-As noted :ref:`in the quick start guide <start-include-jquery>`, the jQuery and jQuery UI libraries 
+As noted :ref:`in the quick start guide <start-include-jquery>`, the jQuery and jQuery UI libraries
 are not included in the distribution but must be included in your templates. For the
-Django admin that means overriding 
+Django admin that means overriding
 `admin/base_site.html <https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/templates/admin/base_site.html>`_.
 You can include this media in the block name `extrahead` which is defined in
 `admin/base.html <https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/templates/admin/base.html>`_.
 See the example project for the full template example.
 
 
+.. _admin-grappelli:
+
+Using Grappelli
+--------------------------------------
+
+.. versionadded:: 0.7
+
+`Grappelli <https://django-grappelli.readthedocs.org>`_ is a popular customization of the Django
+admin interface. It includes a number of interface improvements which are also built on top of
+jQuery UI. When using Grappelli you do not need to make any changes to the ``admin/base_site.html``
+template. django-selectable will detect jQuery and jQuery UI versions included by Grappelli
+and make use of them.
+
+
 .. _admin-basic-example:
 
 Basic Example
 --------------------------------------
 
-In our sample project we have a ``Farm`` model with a foreign key to ``auth.User`` and 
+In our sample project we have a ``Farm`` model with a foreign key to ``auth.User`` and
 a many to many relation to our ``Fruit`` model.
 
     .. literalinclude:: ../example/core/models.py
     .. literalinclude:: ../example/core/admin.py
         :pyobject: FarmAdmin
 
-You'll note this form also for new users to be created and associated with the
-farm if no user is found matching the given name. To make use of this feature we
+You'll note this form also allows new users to be created and associated with the
+farm, if no user is found matching the given name. To make use of this feature we
 need to add ``owner`` to the exclude so that it will pass model validation. Unfortunately
 that means we must set the owner manual in the save and in the initial data because
 the ``ModelForm`` will no longer do this for you. Since ``fruit`` does not allow new
 items you'll see these steps are not necessary.
 
-.. versionadded:: 0.4
-
-The django-selectable widgets are compatitible with the add anther popup in the
+The django-selectable widgets are compatitible with the add another popup in the
 admin. It's that little green plus sign that appears next to ``ForeignKey`` or
 ``ManyToManyField`` items. This makes django-selectable a user friendly replacement
-for the `ModelAdmin.raw_id_fields <https://docs.djangoproject.com/en/1.3/ref/contrib/admin/#django.contrib.admin.ModelAdmin.raw_id_fields>`_ 
+for the `ModelAdmin.raw_id_fields <https://docs.djangoproject.com/en/1.3/ref/contrib/admin/#django.contrib.admin.ModelAdmin.raw_id_fields>`_
 when the default select box grows too long.
 
 
 --------------------------------------
 
 With our ``Farm`` model we can also associate the ``UserAdmin`` with a ``Farm``
-by making use of the `InlineModelAdmin 
+by making use of the `InlineModelAdmin
 <http://docs.djangoproject.com/en/1.3/ref/contrib/admin/#inlinemodeladmin-objects>`_.
 We can even make use of the same ``FarmAdminForm``.
 

docs/advanced.rst

                 super(FruitForm, self).__init__(*args, **kwargs)
                 self.fields['autocomplete'].widget.update_query_parameters({'foo': 'bar'})
 
-.. versionadded:: 0.4
-
 You can also pass the query parameters into the widget using the ``query_params``
 keyword argument. It depends on your use case as to whether the parameters are
 know when the form is defined or when an instance of the form is created.
 
 There are times where you want to filter the result set based other selections
 by the user such as a filtering cities by a previously selected state. In this
-case you will need to bind a ``prepareQuery`` to the field. This function should accept the query dictionary. 
+case you will need to bind a ``prepareQuery`` to the field. This function should accept the query dictionary.
 You are free to make adjustments to  the query dictionary as needed.
 
     .. code-block:: html
             });
         </script>
 
+.. note::
+
+    In v0.7 the scope of ``prepareQuery`` was updated so that ``this`` refers to the
+    current ``djselectable`` plugin instance. Previously ``this`` refered to the
+    plugin ``options`` instance.
+
 
 .. _chain-select-example:
 
 --------------------------------------
 
 It's a fairly common pattern to have two or more inputs depend one another such City/State/Zip.
-In fact there are other Django apps dedicated to this purpose such as 
+In fact there are other Django apps dedicated to this purpose such as
 `django-smart-selects <https://github.com/digi604/django-smart-selects>`_ or
 `django-ajax-filtered-fields <http://code.google.com/p/django-ajax-filtered-fields/>`_.
 It's possible to handle this kind of selection with django-selectable if you are willing
         :pyobject: ChainedForm
 
 We want our users to select a city and if they choose a state then we will only
-show them cities in that state. To do this we will pass back chosen state as 
+show them cities in that state. To do this we will pass back chosen state as
 addition parameter with the following javascript:
 
     .. literalinclude:: ../example/core/templates/advanced.html
 Detecting Client Side Changes
 ____________________________________________
 
-Our previous example made us of detecting changes to the selection on the client
-side to pass new parameters to the lookup. Since django-selectable is built on top of the jQuery UI 
+The previous example detected selection changes on the client side to allow passing
+parameters to the lookup. Since django-selectable is built on top of the jQuery UI
 `Autocomplete plug-in <http://jqueryui.com/demos/autocomplete/>`_, the widgets
 expose the events defined by the plugin.
 
-    - autocompletecreate
-    - autocompletesearch
-    - autocompleteopen
-    - autocompletefocus
-    - autocompleteselect
-    - autocompleteclose
-    - autocompletechange
+    - djselectablecreate
+    - djselectablesearch
+    - djselectableopen
+    - djselectablefocus
+    - djselectableselect
+    - djselectableclose
+    - djselectablechange
+
+.. note::
+
+    Prior to v0.7 these event names were under the ``autocomplete`` namespace. If you
+    are upgrading from a previous version and had customizations using these events
+    you should be sure to update the names.
 
 For the most part these event names should be self-explanatory. If you need additional
 detail you should refer to the `jQuery UI docs on these events <http://jqueryui.com/demos/autocomplete/#events>`_.
 --------------------------------------
 
 You might want to help your users by submitting the form once they have selected a valid
-item. To do this you simply need to listen for the ``autocompleteselect`` event. This
+item. To do this you simply need to listen for the ``djselectableselect`` event. This
 event is fired by the text input which has an index of 0. If your field is named ``my_field``
 then input to watch would be ``my_field_0`` such as:
 
 
         <script type="text/javascript">
             $(document).ready(function() {
-                $(':input[name=my_field_0]').bind('autocompleteselect', function(event, ui) {
+                $(':input[name=my_field_0]').bind('djselectableselect', function(event, ui) {
                     $(this).parents("form").submit();
                 });
             });
 
 django-selectable can work with dynamically added forms such as inlines in the admin.
 To make django-selectable work in the admin there is nothing more to do than include
-the necessary static media as described in the 
+the necessary static media as described in the
 :ref:`Admin Integration <admin-jquery-include>` section.
 
 If you are making use of the popular `django-dynamic-formset <http://code.google.com/p/django-dynamic-formset/>`_
-then you can make django-selectable work by passing ``bindSelectables`` to the 
+then you can make django-selectable work by passing ``bindSelectables`` to the
 `added <http://code.google.com/p/django-dynamic-formset/source/browse/trunk/docs/usage.txt#259>`_ option:
 
     .. code-block:: html
         <script type="text/javascript">
             $(document).ready(function() {
                 $('#my-formset').formset({
-               		added: bindSelectables	
+               		added: bindSelectables
                 });
             });
         </script>
 :ref:`format_item <lookup-format-item>`. ``formatLabel`` should return the string
 which should be used for the label.
 
+.. note::
+
+    In v0.7 the scope of ``formatLabel`` was updated so that ``this`` refers to the
+    current ``djselectable`` plugin instance. Previously ``this`` refered to the
+    plugin ``options`` instance.
+
 Going back to the ``CityLookup`` we can adjust the label to wrap the city and state
 portions with their own classes for additional styling:
 
 
 This is a rather simple example but you could also pass additional information in ``format_item``
 such as a flag of whether the city is the capital and render the state captials differently.
+
+.. _advanced-bootstrap:
+
+Using with Twitter Bootstrap
+--------------------------------------
+
+django-selectable can work along side with Twitter Bootstrap but there are a few things to
+take into consideration. Both jQuery UI and Bootstrap define a ``$.button`` plugin. This
+plugin is used by default by django-selectable and expects the UI version. If the jQuery UI
+JS is included after the Bootstrap JS then this will work just fine but the Bootstrap
+button JS will not be available. This is the strategy taken by the  `jQuery UI Bootstrap
+<http://addyosmani.github.com/jquery-ui-bootstrap/>`_ theme.
+
+Another option is to rename the Bootstrap plugin using the ``noConflict`` option.
+
+    .. code-block:: html
+
+        <!-- Include Bootstrap JS -->
+        <script>$.fn.bootstrapBtn = $.fn.button.noConflict();</script>
+        <!-- Include jQuery UI JS -->
+
+Even with this some might complain that it's too resource heavy to include all of
+jQuery UI when you just want the autocomplete to work with django-selectable. For
+this you can use the `Download Builder <http://jqueryui.com/download/>`_ to build
+a minimal set of jQuery UI widgets. django-selectable requires the UI core, autocomplete,
+menu and button widgets. None of the effects or interactions are needed. Minified
+this totals around 100 kb of JS, CSS and images (based on jQuery UI 1.10).
+
+.. note::
+
+    For a comparison this is smaller than the minified Bootstrap 2.3.0 CSS
+    which is 105 kb not including the responsive CSS or the icon graphics.
+
+It is possible to remove the dependency on the UI button plugin and instead
+use the Bootstrap button styles. This is done by overriding
+the ``_comboButtonTemplate`` and ``_removeButtonTemplate`` functions used to
+create the buttons. An example is given below.
+
+    .. code-block:: html
+
+        <script>
+            $.ui.djselectable.prototype._comboButtonTemplate = function (input) {
+                var icon = $("<i>").addClass("icon-chevron-down");
+                // Remove current classes on the text input
+                $(input).attr("class", "");
+                // Wrap with input-append
+                $(input).wrap('<div class="input-append" />');
+                // Return button link with the chosen icon
+                return $("<a>").append(icon).addClass("btn btn-small");
+            };
+            $.ui.djselectable.prototype._removeButtonTemplate = function (item) {
+                var icon = $("<i>").addClass("icon-remove-sign");
+                // Return button link with the chosen icon
+                return $("<a>").append(icon).addClass("btn btn-small pull-right");
+            };
+        </script>
 
 # General information about the project.
 project = u'Django-Selectable'
-copyright = u'2011-2012, Mark Lavin'
+copyright = u'2011-2013, Mark Lavin'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
 # The short X.Y version.
-version = '0.6'
+version = '0.7'
 # The full version, including alpha/beta/rc tags.
-release = '0.6.2'
+release = '0.7.0dev'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.

docs/contribute.rst

 
     python runtests.py
 
-Client side tests are written using `QUnit <http://docs.jquery.com/QUnit>`_. They
-can be found in `selectable/tests/qunit/`.
-
 `tox <http://tox.readthedocs.org/en/latest/index.html>`_ is used to test django-selectable
 against multiple versions of Django/Python. With tox installed you can run::
 
 
 to run all the version combinations. You can also run tox against a subset of supported
 environments::
-    
-    tox -e py26-1.2.X,py26-1.3.X,py26
 
-This example will run the test against the latest 1.4.X, 1.3.X and 1.2.X releases
-using Python 2.6. For more information on running/installing tox please see the
+    tox -e py26-1.4.X
+
+This example will run the test against the latest 1.5.X, 1.4.X, and 1.3.X releases
+using Python 2.6 and 3.2 for 1.5+. For more information on running/installing tox please see the
 tox documentation: http://tox.readthedocs.org/en/latest/index.html
 
+Client side tests are written using `QUnit <http://docs.jquery.com/QUnit>`_. They
+can be found in ``selectable/tests/qunit/index.html``. The test suite also uses
+`Grunt <https://github.com/gruntjs/grunt>`_ and `PhantomJS <http://phantomjs.org/>`_ to
+run the tests. You can install Grunt and PhantomJS from NPM::
+
+    # Install grunt requirements
+    npm install -g grunt phantomjs jshint
+    # Execute default grunt tasks
+    grunt
+
 
 Building the Documentation
 --------------------------------------
 
-The documentation is built using `Sphinx <http://sphinx.pocoo.org/>`_ 
+The documentation is built using `Sphinx <http://sphinx.pocoo.org/>`_
 and available on `Read the Docs <http://django-selectable.readthedocs.org/>`_. With
 Sphinx installed you can build the documentation by running::
 
 
 AutoCompleteSelectField
 --------------------------------------
-    
-Field tied to :ref:`AutoCompleteSelectWidget` to bind the selection to the form and  
+
+Field tied to :ref:`AutoCompleteSelectWidget` to bind the selection to the form and
 create new items, if allowed. The ``allow_new`` keyword argument (default: ``False``)
 which determines if the field allows new items. This field cleans to a single item.
 
         :end-before: # AutoCompleteSelectField (allows new items)
 
 
-.. _AutoComboboxSelectField:
+.. versionadded:: 0.7
 
-AutoComboboxSelectField
---------------------------------------
+`lookup_class`` may also be a dotted path.
 
-.. deprecated:: 0.5
+    .. code-block:: python
 
-This field is deprecated in v0.5 and removed in v0.6. You should instead
-use the above :ref:`AutoCompleteSelectField` and pass the :ref:`AutoComboboxSelectWidget`
-in the ``widget`` argument.
+	    selectable.AutoCompleteSelectField(lookup_class='core.lookups.FruitLookup')
 
 
 .. _AutoCompleteSelectMultipleField:
     .. literalinclude:: ../example/core/forms.py
         :start-after: # AutoCompleteSelectMultipleField
         :end-before: # AutoComboboxSelectMultipleField
-
-
-.. _AutoComboboxSelectMultipleField:
-
-AutoComboboxSelectMultipleField
---------------------------------------
-
-.. deprecated:: 0.5
-
-This field is deprecated in v0.5 and removed in v0.6. You should instead
-use the above :ref:`AutoCompleteSelectMultipleField` and pass the 
-:ref:`AutoComboboxSelectMultipleWidget` in the ``widget`` argument.
     quick-start
     lookups
     advanced
-    admin    
+    admin
+    testing
     fields
     widgets
     settings

docs/quick-start.rst

 
 The jQuery and jQuery UI libraries are not included in the distribution but must be included
 in your templates. However there is a template tag to easily add these libraries from
-the  from the `Google CDN <http://code.google.com/apis/libraries/devguide.html#jquery>`_. 
+the  from the `Google CDN <http://code.google.com/apis/libraries/devguide.html#jquery>`_.
 
     .. code-block:: html
 
         {% load selectable_tags %}
         {% include_jquery_libs '1.4.4' '1.8.13' %}
 
-Django-Selectable should work with `jQuery <http://jquery.com/>`_ >= 1.4.4 and 
+Django-Selectable should work with `jQuery <http://jquery.com/>`_ >= 1.4.4 and
 `jQuery UI <http://jqueryui.com/>`_ >= 1.8.13.
 
 You must also include a `jQuery UI theme <http://jqueryui.com/themeroller/>`_ stylesheet. There
 
 See the the jQuery UI documentation for a full list of available stable themes: http://jqueryui.com/download#stable-themes
 
+Of course you can choose to include these rescources manually::
+
+    .. code-block:: html
+
+        <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/themes/base/jquery-ui.css" type="text/css">
+        <link href="{{ STATIC_URL }}selectable/css/dj.selectable.css" type="text/css" media="all" rel="stylesheet">
+        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
+        <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/jquery-ui.js"></script>
+        <script type="text/javascript" src="{{ STATIC_URL }}selectable/js/jquery.dj.selectable.js"></script>
+
 .. note::
 
-    These template tags were added in v0.5.0. Prior to that these js/css resources
-    need to be added manually.
+    jQuery UI shares a few plugin names with the popular Twitter Bootstrap framework. There
+    are notes on using Bootstrap along with django-selectable in the :ref:`advanced usage
+    section <advanced-bootstrap>`.
 
 
 Defining a Lookup

docs/releases.rst

 Release Notes
 ==================
 
+v0.7.0 (Released TBD)
+--------------------------------------
+
+This release features a large refactor of the JS plugin used by the widgets. While this
+over makes the plugin more maintainable and allowed for some of the new features in this
+release, it does introduce a few incompatible changes. For the most part places where you
+might have previously used the ``autocomplete`` namespace/plugin, those references should
+be updated to reference the ``djselectable`` plugin.
+
+This release also adds experimental support for Python 3.2+ to go along with Django's support in 1.5.
+To use Python 3 with django-selectable you will need to use Django 1.5+.
+
+- Experimental Python 3.2+ support
+- Improved the scope of ``prepareQuery`` and ``formatLabel`` options. Not fully backwards compatible. Thanks to Augusto Men.
+- Allow passing the Python path string in place of the lookup class to the fields and widgets. Thanks to Michael Manfre.
+- Allow passing JS plugin options through the widget ``attrs`` option. Thanks to Felipe Prenholato.
+- Tests for compatibility with jQuery 1.6 through 1.9 and jQuery UI 1.8 through 1.10.
+- Added notes on Bootstrap compatibility.
+- Added compatibility with Grappelli in the admin.
+- Added Spanish translation thanks to Manuel Alvarez.
+- Added documentation notes on testing.
+
+Bug Fixes
+_________________
+
+- Fixed bug with matching hidden input when the name contains '_1'. Thanks to Augusto Men for the report and fix.
+- Fixed bug where the enter button would open the combobox options rather than submit the form. Thanks to Felipe Prenholato for the report.
+- Fixed bug with using ``allow_new=True`` creating items when no data was submitted. See #91.
+- Fixed bug with widget ``has_changed`` when there is no initial data. See #92.
+
+
+Backwards Incompatible Changes
+________________________________
+
+- The JS event namespace has changed from ``autocomplete`` to ``djselectable``.
+- ``data('autocomplete')`` is no longer available on the widgets on the client-side. Use ``data('djselectable')`` instead.
+- Combobox button was changed from a ``<button>`` to ``<a>``. Any customized styles you may have should be updated.
+- Combobox no longer changes the ``minLength`` or ``delay`` options.
+
 
 v0.6.2 (Released 2012-11-07)
 --------------------------------------
 ________________________________
 
 - Previously the minimal version of jQuery was listed as 1.4.3 when it fact there was a bug a that made django-selectable require 1.4.4. Not a new incompatibility but the docs have now been updated and 1.4.3 compatibility will not be added. Thanks to Rick Testore for the report and the fix
-- Started deprecation path for :ref:`AutoComboboxSelectField` and :ref:`AutoComboboxSelectMultipleField`
+- Started deprecation path for AutoComboboxSelectField and AutoComboboxSelectMultipleField
 
 
 v0.4.1 (Released 2012-03-11)
+Testing Forms and Lookups
+====================================
+
+django-selectable has its own test suite for testing the rendering, validation
+and server-side logic it provides. However, depending on the additional customizations
+you add to your forms and lookups you most likely will want to include tests of your
+own. This section contains some tips or techniques for testing your lookups.
+
+This guide assumes that you are reasonable familiar with the concepts of unit testing
+including Python's `unittest <http://docs.python.org/2/library/unittest.html>`_ module and
+Django's `testing guide <https://docs.djangoproject.com/en/1.4/topics/testing/>`_.
+
+
+Testing Forms with django-selectable
+--------------------------------------------------
+
+For the most part testing forms which use django-selectable's custom fields
+and widgets is the same as testing any Django form. One point that is slightly
+different is that the select and multi-select widgets are
+`MultiWidgets <https://docs.djangoproject.com/en/1.4/ref/forms/widgets/#django.forms.MultiWidget>`_.
+The effect of this is that there are two names in the post rather than one. Take the below
+form for example.
+
+    .. code-block:: python
+
+        # models.py
+
+        from django.db import models
+
+        class Thing(models.Model):
+            name = models.CharField(max_length=100)
+            description = models.CharField(max_length=100)
+
+            def __unicode__(self):
+                return self.name
+
+    .. code-block:: python
+
+        # lookups.py
+
+        from selectable.base import ModelLookup
+        from selectable.registry import registry
+
+        from .models import Thing
+
+        class ThingLookup(ModelLookup):
+            model = Thing
+            search_fields = ('name__icontains', )
+
+        registry.register(ThingLookup)
+
+    .. code-block:: python
+
+        # forms.py
+
+        from django import forms
+
+        from selectable.forms import AutoCompleteSelectField
+
+        from .lookups import ThingLookup
+
+        class SimpleForm(forms.Form):
+            "Basic form for testing."
+            thing = AutoCompleteSelectField(lookup_class=ThingLookup)
+
+This form has a single field to select a ``Thing``. It does not allow
+new items. Let's write some simple tests for this form.
+
+    .. code-block:: python
+
+        # tests.py
+
+        from django.test import TestCase
+
+        from .forms import SimpleForm
+        from .models import Thing
+
+        class SimpleFormTestCase(TestCase):
+
+            def test_valid_form(self):
+                "Submit valid data."
+                thing = Thing.objects.create(name='Foo', description='Bar')
+                data = {
+                    'thing_0': thing.name,
+                    'thing_1': thing.pk,
+                }
+                form = SimpleForm(data=data)
+                self.assertTrue(form.is_valid())
+
+            def test_invalid_form(self):
+                "Thing is required but missing."
+                data = {
+                    'thing_0': 'Foo',
+                    'thing_1': '',
+                }
+                form = SimpleForm(data=data)
+                self.assertFalse(form.is_valid())
+
+Here you will note that while there is only one field ``thing`` it requires
+two items in the POST the first is for the text input and the second is for
+the hidden input. This is again due to the use of MultiWidget for the selection.
+
+
+Testing Lookup Results
+--------------------------------------------------
+
+Testing the lookups used by django-selectable is similar to testing your Django views.
+While it might be tempting to use the Django
+`test client <https://docs.djangoproject.com/en/1.4/topics/testing/#module-django.test.client>`_,
+it is slightly easier to use the
+`request factory <https://docs.djangoproject.com/en/1.4/topics/testing/#the-request-factory>`_.
+A simple example is given below.
+
+    .. code-block:: python
+
+        # tests.py
+
+        import json
+
+        from django.test import TestCase
+        from django.test.client import RequestFactory
+
+        from .lookups import ThingLookup
+        from .models import Thing
+
+        class ThingLookupTestCase(TestCase):
+
+            def setUp(self):
+                self.factory = RequestFactory()
+                self.lookup = ThingLookup()
+                self.test_thing = Thing.objects.create(name='Foo', description='Bar')
+
+            def test_results(self):
+                "Test full response."
+                request = self.factory.get("/", {'term': 'Fo'})
+                response = self.lookup.results(request)
+                data = json.loads(response.content)['data']
+                self.assertEqual(1, len(data))
+                self.assertEqual(self.test_thing.pk, data[1]['id'])
+
+            def test_label(self):
+                "Test item label."
+                label = self.lookup.get_item_label(self.test_thing)
+                self.assertEqual(self.test_thing.name, label)
+
+As shown in the ``test_label`` example it is not required to test the full
+request/response. You can test each of the methods in the lookup API individually.
+When testing your lookups you should focus on testing the portions which have been
+customized by your application.
 Widgets
 ==========
 
-Below are the custom widgets defined by Django-Selectable. All widgets take the 
+Below are the custom widgets defined by Django-Selectable. All widgets take the
 lookup class as the first required argument.
 
-.. versionadded:: 0.4
-
 These widgets all support a ``query_params`` keyword argument which is used to pass
-additional query parameters to the lookup search. See the section on 
+additional query parameters to the lookup search. See the section on
 :ref:`Adding Parameters on the Server Side <server-side-parameters>` for more
 information.
 
+.. versionadded:: 0.7
+
+You can configure the plugin options by passing the configuration dictionary in the ``data-selectable-options``
+attribute. The set of options availble include those define by the base
+`autocomplete plugin <http://api.jqueryui.com/1.9/autocomplete/>`_ as well as the
+:ref:`javascript-removeIcon`, :ref:`javascript-comboboxIcon`, and :ref:`javascript-highlightMatch` options
+which are unique to django-selectable.
+
+    .. code-block:: python
+
+        attrs = {'data-selectable-options': {'highlightMatch': True, 'minLength': 5}}
+        selectable.AutoCompleteSelectWidget(lookup_class=FruitLookup, attrs=attrs)
+
 
 .. _AutoCompleteWidget:
 
 by the lookup ``get_item_value``. If the ``allow_new`` keyword argument is passed as
 true it will allow the user to type any text they wish.
 
-
 .. _AutoComboboxWidget:
 
 AutoComboboxWidget
 This widget should be used in conjunction with the :ref:`AutoCompleteSelectField` as it will
 return both the text entered by the user and the id (if an item was selected/matched).
 
-.. versionadded:: 0.4
-
-Prior to 0.4 :ref:`AutoCompleteSelectWidget` could not work directly with Django's
+:ref:`AutoCompleteSelectWidget` works directly with Django's
 `ModelChoiceField <https://docs.djangoproject.com/en/1.3/ref/forms/fields/#modelchoicefield>`_.
-Starting with 0.4 you can simply replace the widget without replacing the entire field.
+You can simply replace the widget without replacing the entire field.
 
     .. code-block:: python
 
 
 The one catch is that you must use ``allow_new=False`` which is the default.
 
+.. versionadded:: 0.7
+
+``lookup_class`` may also be a dotted path.
+
+    .. code-block:: python
+
+         widget = selectable.AutoCompleteWidget(lookup_class='core.lookups.FruitLookup')
+
 
 .. _AutoComboboxSelectWidget:
 
 
 Similar to :ref:`AutoCompleteSelectWidget` but has a button to reveal all options.
 
-.. versionadded:: 0.4
-
-Prior to 0.4 :ref:`AutoComboboxSelectWidget` could not work directly with Django's
+:ref:`AutoComboboxSelectWidget` works directly with Django's
 `ModelChoiceField <https://docs.djangoproject.com/en/1.3/ref/forms/fields/#modelchoicefield>`_.
-Starting with 0.4 you can simply replace the widget without replacing the entire field.
+You can simply replace the widget without replacing the entire field.
 
     .. code-block:: python
 

example/core/admin.py

     def __init__(self, *args, **kwargs):
         super(FarmAdminForm, self).__init__(*args, **kwargs)
         if self.instance and self.instance.pk and self.instance.owner:
-            self.initial['owner'] = self.instance.owner
+            self.initial['owner'] = self.instance.owner.pk
 
     def save(self, *args, **kwargs):
         owner = self.cleaned_data['owner']

example/core/lookups.py

+from __future__ import unicode_literals
+
 from django.contrib.auth.models import User
 
 from selectable.base import ModelLookup
         return results
 
     def get_item_label(self, item):
-        return u"%s, %s" % (item.name, item.state)
+        return "%s, %s" % (item.name, item.state)
 
 
 registry.register(CityLookup)

example/core/models.py

+from __future__ import unicode_literals
+
 from django.contrib.localflavor.us.models import USStateField
 from django.db import models
 
     fruit = models.ManyToManyField(Fruit)
 
     def __unicode__(self):
-        return u"%s's Farm: %s" % (self.owner.username, self.name)
+        return "%s's Farm: %s" % (self.owner.username, self.name)
 
 
 class City(models.Model):
     name = models.CharField(max_length=200)
     state = USStateField()
-    
+
     def __unicode__(self):
         return self.name

example/example/static/css/bootstrap-responsive.css

+/*!
+ * Bootstrap Responsive v2.3.0
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+
+.clearfix {
+  *zoom: 1;
+}
+
+.clearfix:before,
+.clearfix:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.clearfix:after {
+  clear: both;
+}
+
+.hide-text {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+
+.input-block-level {
+  display: block;
+  width: 100%;
+  min-height: 30px;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+@-ms-viewport {
+  width: device-width;
+}
+
+.hidden {
+  display: none;
+  visibility: hidden;
+}
+
+.visible-phone {
+  display: none !important;
+}
+
+.visible-tablet {
+  display: none !important;
+}
+
+.hidden-desktop {
+  display: none !important;
+}
+
+.visible-desktop {
+  display: inherit !important;
+}
+
+@media (min-width: 768px) and (max-width: 979px) {
+  .hidden-desktop {
+    display: inherit !important;
+  }
+  .visible-desktop {
+    display: none !important ;
+  }
+  .visible-tablet {
+    display: inherit !important;
+  }
+  .hidden-tablet {
+    display: none !important;
+  }
+}
+
+@media (max-width: 767px) {
+  .hidden-desktop {
+    display: inherit !important;
+  }
+  .visible-desktop {
+    display: none !important;
+  }
+  .visible-phone {
+    display: inherit !important;
+  }
+  .hidden-phone {
+    display: none !important;
+  }
+}
+
+.visible-print {
+  display: none !important;
+}
+
+@media print {
+  .visible-print {
+    display: inherit !important;
+  }
+  .hidden-print {
+    display: none !important;
+  }
+}
+
+@media (min-width: 1200px) {
+  .row {
+    margin-left: -30px;
+    *zoom: 1;
+  }
+  .row:before,
+  .row:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row:after {
+    clear: both;
+  }
+  [class*="span"] {
+    float: left;
+    min-height: 1px;
+    margin-left: 30px;
+  }
+  .container,
+  .navbar-static-top .container,
+  .navbar-fixed-top .container,
+  .navbar-fixed-bottom .container {
+    width: 1170px;
+  }
+  .span12 {
+    width: 1170px;
+  }
+  .span11 {
+    width: 1070px;
+  }
+  .span10 {
+    width: 970px;
+  }
+  .span9 {
+    width: 870px;
+  }
+  .span8 {
+    width: 770px;
+  }
+  .span7 {
+    width: 670px;
+  }
+  .span6 {
+    width: 570px;
+  }
+  .span5 {
+    width: 470px;
+  }
+  .span4 {
+    width: 370px;
+  }
+  .span3 {
+    width: 270px;
+  }
+  .span2 {
+    width: 170px;
+  }
+  .span1 {
+    width: 70px;
+  }
+  .offset12 {
+    margin-left: 1230px;
+  }
+  .offset11 {
+    margin-left: 1130px;
+  }
+  .offset10 {
+    margin-left: 1030px;
+  }
+  .offset9 {
+    margin-left: 930px;
+  }
+  .offset8 {
+    margin-left: 830px;
+  }
+  .offset7 {
+    margin-left: 730px;
+  }
+  .offset6 {
+    margin-left: 630px;
+  }
+  .offset5 {
+    margin-left: 530px;
+  }
+  .offset4 {
+    margin-left: 430px;
+  }
+  .offset3 {
+    margin-left: 330px;
+  }
+  .offset2 {
+    margin-left: 230px;
+  }
+  .offset1 {
+    margin-left: 130px;
+  }
+  .row-fluid {
+    width: 100%;
+    *zoom: 1;
+  }
+  .row-fluid:before,
+  .row-fluid:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row-fluid:after {
+    clear: both;
+  }
+  .row-fluid [class*="span"] {
+    display: block;
+    float: left;
+    width: 100%;
+    min-height: 30px;
+    margin-left: 2.564102564102564%;
+    *margin-left: 2.5109110747408616%;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .row-fluid [class*="span"]:first-child {
+    margin-left: 0;
+  }
+  .row-fluid .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 2.564102564102564%;
+  }
+  .row-fluid .span12 {
+    width: 100%;
+    *width: 99.94680851063829%;
+  }
+  .row-fluid .span11 {
+    width: 91.45299145299145%;
+    *width: 91.39979996362975%;
+  }
+  .row-fluid .span10 {
+    width: 82.90598290598291%;
+    *width: 82.8527914166212%;
+  }
+  .row-fluid .span9 {
+    width: 74.35897435897436%;
+    *width: 74.30578286961266%;
+  }
+  .row-fluid .span8 {
+    width: 65.81196581196582%;
+    *width: 65.75877432260411%;
+  }
+  .row-fluid .span7 {
+    width: 57.26495726495726%;
+    *width: 57.21176577559556%;
+  }
+  .row-fluid .span6 {
+    width: 48.717948717948715%;
+    *width: 48.664757228587014%;
+  }
+  .row-fluid .span5 {
+    width: 40.17094017094017%;
+    *width: 40.11774868157847%;
+  }
+  .row-fluid .span4 {
+    width: 31.623931623931625%;
+    *width: 31.570740134569924%;
+  }
+  .row-fluid .span3 {
+    width: 23.076923076923077%;
+    *width: 23.023731587561375%;
+  }
+  .row-fluid .span2 {
+    width: 14.52991452991453%;
+    *width: 14.476723040552828%;
+  }
+  .row-fluid .span1 {
+    width: 5.982905982905983%;
+    *width: 5.929714493544281%;
+  }
+  .row-fluid .offset12 {
+    margin-left: 105.12820512820512%;
+    *margin-left: 105.02182214948171%;
+  }
+  .row-fluid .offset12:first-child {
+    margin-left: 102.56410256410257%;
+    *margin-left: 102.45771958537915%;
+  }
+  .row-fluid .offset11 {
+    margin-left: 96.58119658119658%;
+    *margin-left: 96.47481360247316%;
+  }
+  .row-fluid .offset11:first-child {
+    margin-left: 94.01709401709402%;
+    *margin-left: 93.91071103837061%;
+  }
+  .row-fluid .offset10 {
+    margin-left: 88.03418803418803%;
+    *margin-left: 87.92780505546462%;
+  }
+  .row-fluid .offset10:first-child {
+    margin-left: 85.47008547008548%;
+    *margin-left: 85.36370249136206%;
+  }
+  .row-fluid .offset9 {
+    margin-left: 79.48717948717949%;
+    *margin-left: 79.38079650845607%;
+  }
+  .row-fluid .offset9:first-child {
+    margin-left: 76.92307692307693%;
+    *margin-left: 76.81669394435352%;
+  }
+  .row-fluid .offset8 {
+    margin-left: 70.94017094017094%;
+    *margin-left: 70.83378796144753%;
+  }
+  .row-fluid .offset8:first-child {
+    margin-left: 68.37606837606839%;
+    *margin-left: 68.26968539734497%;
+  }
+  .row-fluid .offset7 {
+    margin-left: 62.393162393162385%;
+    *margin-left: 62.28677941443899%;
+  }
+  .row-fluid .offset7:first-child {
+    margin-left: 59.82905982905982%;
+    *margin-left: 59.72267685033642%;
+  }
+  .row-fluid .offset6 {
+    margin-left: 53.84615384615384%;
+    *margin-left: 53.739770867430444%;
+  }
+  .row-fluid .offset6:first-child {
+    margin-left: 51.28205128205128%;
+    *margin-left: 51.175668303327875%;
+  }
+  .row-fluid .offset5 {
+    margin-left: 45.299145299145295%;
+    *margin-left: 45.1927623204219%;
+  }
+  .row-fluid .offset5:first-child {
+    margin-left: 42.73504273504273%;
+    *margin-left: 42.62865975631933%;
+  }
+  .row-fluid .offset4 {
+    margin-left: 36.75213675213675%;
+    *margin-left: 36.645753773413354%;
+  }
+  .row-fluid .offset4:first-child {
+    margin-left: 34.18803418803419%;
+    *margin-left: 34.081651209310785%;
+  }
+  .row-fluid .offset3 {
+    margin-left: 28.205128205128204%;
+    *margin-left: 28.0987452264048%;
+  }
+  .row-fluid .offset3:first-child {
+    margin-left: 25.641025641025642%;
+    *margin-left: 25.53464266230224%;
+  }
+  .row-fluid .offset2 {
+    margin-left: 19.65811965811966%;
+    *margin-left: 19.551736679396257%;
+  }
+  .row-fluid .offset2:first-child {
+    margin-left: 17.094017094017094%;
+    *margin-left: 16.98763411529369%;
+  }
+  .row-fluid .offset1 {
+    margin-left: 11.11111111111111%;
+    *margin-left: 11.004728132387708%;
+  }
+  .row-fluid .offset1:first-child {
+    margin-left: 8.547008547008547%;
+    *margin-left: 8.440625568285142%;
+  }
+  input,
+  textarea,
+  .uneditable-input {
+    margin-left: 0;
+  }
+  .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 30px;
+  }
+  input.span12,
+  textarea.span12,
+  .uneditable-input.span12 {
+    width: 1156px;
+  }
+  input.span11,
+  textarea.span11,
+  .uneditable-input.span11 {
+    width: 1056px;
+  }
+  input.span10,
+  textarea.span10,
+  .uneditable-input.span10 {
+    width: 956px;
+  }
+  input.span9,
+  textarea.span9,
+  .uneditable-input.span9 {
+    width: 856px;
+  }
+  input.span8,
+  textarea.span8,
+  .uneditable-input.span8 {
+    width: 756px;
+  }
+  input.span7,
+  textarea.span7,
+  .uneditable-input.span7 {
+    width: 656px;
+  }
+  input.span6,
+  textarea.span6,
+  .uneditable-input.span6 {
+    width: 556px;
+  }
+  input.span5,
+  textarea.span5,
+  .uneditable-input.span5 {
+    width: 456px;
+  }
+  input.span4,
+  textarea.span4,
+  .uneditable-input.span4 {
+    width: 356px;
+  }
+  input.span3,
+  textarea.span3,
+  .uneditable-input.span3 {
+    width: 256px;
+  }
+  input.span2,
+  textarea.span2,
+  .uneditable-input.span2 {
+    width: 156px;
+  }
+  input.span1,
+  textarea.span1,
+  .uneditable-input.span1 {
+    width: 56px;
+  }
+  .thumbnails {
+    margin-left: -30px;
+  }
+  .thumbnails > li {
+    margin-left: 30px;
+  }
+  .row-fluid .thumbnails {
+    margin-left: 0;
+  }
+}
+
+@media (min-width: 768px) and (max-width: 979px) {
+  .row {
+    margin-left: -20px;
+    *zoom: 1;
+  }
+  .row:before,
+  .row:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row:after {
+    clear: both;
+  }
+  [class*="span"] {
+    float: left;
+    min-height: 1px;
+    margin-left: 20px;
+  }
+  .container,
+  .navbar-static-top .container,
+  .navbar-fixed-top .container,
+  .navbar-fixed-bottom .container {
+    width: 724px;
+  }
+  .span12 {
+    width: 724px;
+  }
+  .span11 {
+    width: 662px;
+  }
+  .span10 {
+    width: 600px;
+  }
+  .span9 {
+    width: 538px;
+  }
+  .span8 {
+    width: 476px;
+  }
+  .span7 {
+    width: 414px;
+  }
+  .span6 {
+    width: 352px;
+  }
+  .span5 {
+    width: 290px;
+  }
+  .span4 {
+    width: 228px;
+  }
+  .span3 {
+    width: 166px;
+  }
+  .span2 {
+    width: 104px;
+  }
+  .span1 {
+    width: 42px;
+  }
+  .offset12 {
+    margin-left: 764px;
+  }
+  .offset11 {
+    margin-left: 702px;
+  }
+  .offset10 {
+    margin-left: 640px;
+  }
+  .offset9 {
+    margin-left: 578px;
+  }
+  .offset8 {
+    margin-left: 516px;
+  }
+  .offset7 {
+    margin-left: 454px;
+  }
+  .offset6 {
+    margin-left: 392px;
+  }
+  .offset5 {
+    margin-left: 330px;
+  }
+  .offset4 {
+    margin-left: 268px;
+  }
+  .offset3 {
+    margin-left: 206px;
+  }
+  .offset2 {
+    margin-left: 144px;
+  }
+  .offset1 {
+    margin-left: 82px;
+  }
+  .row-fluid {
+    width: 100%;
+    *zoom: 1;
+  }
+  .row-fluid:before,
+  .row-fluid:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row-fluid:after {
+    clear: both;
+  }
+  .row-fluid [class*="span"] {
+    display: block;
+    float: left;
+    width: 100%;
+    min-height: 30px;
+    margin-left: 2.7624309392265194%;
+    *margin-left: 2.709239449864817%;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .row-fluid [class*="span"]:first-child {
+    margin-left: 0;
+  }
+  .row-fluid .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 2.7624309392265194%;
+  }
+  .row-fluid .span12 {
+    width: 100%;
+    *width: 99.94680851063829%;
+  }
+  .row-fluid .span11 {
+    width: 91.43646408839778%;
+    *width: 91.38327259903608%;
+  }
+  .row-fluid .span10 {
+    width: 82.87292817679558%;
+    *width: 82.81973668743387%;
+  }
+  .row-fluid .span9 {
+    width: 74.30939226519337%;
+    *width: 74.25620077583166%;
+  }
+  .row-fluid .span8 {
+    width: 65.74585635359117%;
+    *width: 65.69266486422946%;
+  }
+  .row-fluid .span7 {
+    width: 57.18232044198895%;
+    *width: 57.12912895262725%;
+  }
+  .row-fluid .span6 {
+    width: 48.61878453038674%;
+    *width: 48.56559304102504%;
+  }
+  .row-fluid .span5 {
+    width: 40.05524861878453%;
+    *width: 40.00205712942283%;
+  }
+  .row-fluid .span4 {
+    width: 31.491712707182323%;
+    *width: 31.43852121782062%;
+  }
+  .row-fluid .span3 {
+    width: 22.92817679558011%;
+    *width: 22.87498530621841%;
+  }
+  .row-fluid .span2 {
+    width: 14.3646408839779%;
+    *width: 14.311449394616199%;
+  }
+  .row-fluid .span1 {
+    width: 5.801104972375691%;
+    *width: 5.747913483013988%;
+  }
+  .row-fluid .offset12 {
+    margin-left: 105.52486187845304%;
+    *margin-left: 105.41847889972962%;
+  }
+  .row-fluid .offset12:first-child {
+    margin-left: 102.76243093922652%;
+    *margin-left: 102.6560479605031%;
+  }
+  .row-fluid .offset11 {
+    margin-left: 96.96132596685082%;
+    *margin-left: 96.8549429881274%;
+  }
+  .row-fluid .offset11:first-child {
+    margin-left: 94.1988950276243%;
+    *margin-left: 94.09251204890089%;
+  }
+  .row-fluid .offset10 {
+    margin-left: 88.39779005524862%;
+    *margin-left: 88.2914070765252%;
+  }
+  .row-fluid .offset10:first-child {
+    margin-left: 85.6353591160221%;
+    *margin-left: 85.52897613729868%;
+  }
+  .row-fluid .offset9 {
+    margin-left: 79.8342541436464%;
+    *margin-left: 79.72787116492299%;
+  }
+  .row-fluid .offset9:first-child {
+    margin-left: 77.07182320441989%;
+    *margin-left: 76.96544022569647%;
+  }
+  .row-fluid .offset8 {
+    margin-left: 71.2707182320442%;
+    *margin-left: 71.16433525332079%;
+  }
+  .row-fluid .offset8:first-child {
+    margin-left: 68.50828729281768%;
+    *margin-left: 68.40190431409427%;
+  }
+  .row-fluid .offset7 {
+    margin-left: 62.70718232044199%;
+    *margin-left: 62.600799341718584%;
+  }
+  .row-fluid .offset7:first-child {
+    margin-left: 59.94475138121547%;
+    *margin-left: 59.838368402492065%;
+  }
+  .row-fluid .offset6 {
+    margin-left: 54.14364640883978%;
+    *margin-left: 54.037263430116376%;
+  }
+  .row-fluid .offset6:first-child {
+    margin-left: 51.38121546961326%;
+    *margin-left: 51.27483249088986%;
+  }
+  .row-fluid .offset5 {
+    margin-left: 45.58011049723757%;
+    *margin-left: 45.47372751851417%;
+  }
+  .row-fluid .offset5:first-child {
+    margin-left: 42.81767955801105%;
+    *margin-left: 42.71129657928765%;
+  }
+  .row-fluid .offset4 {
+    margin-left: 37.01657458563536%;
+    *margin-left: 36.91019160691196%;
+  }
+  .row-fluid .offset4:first-child {
+    margin-left: 34.25414364640884%;
+    *margin-left: 34.14776066768544%;
+  }
+  .row-fluid .offset3 {
+    margin-left: 28.45303867403315%;
+    *margin-left: 28.346655695309746%;
+  }
+  .row-fluid .offset3:first-child {
+    margin-left: 25.69060773480663%;
+    *margin-left: 25.584224756083227%;
+  }
+  .row-fluid .offset2 {
+    margin-left: 19.88950276243094%;
+    *margin-left: 19.783119783707537%;
+  }
+  .row-fluid .offset2:first-child {
+    margin-left: 17.12707182320442%;
+    *margin-left: 17.02068884448102%;
+  }
+  .row-fluid .offset1 {
+    margin-left: 11.32596685082873%;
+    *margin-left: 11.219583872105325%;
+  }
+  .row-fluid .offset1:first-child {
+    margin-left: 8.56353591160221%;
+    *margin-left: 8.457152932878806%;
+  }
+  input,
+  textarea,
+  .uneditable-input {
+    margin-left: 0;
+  }
+  .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 20px;
+  }
+  input.span12,
+  textarea.span12,
+  .uneditable-input.span12 {
+    width: 710px;
+  }
+  input.span11,
+  textarea.span11,
+  .uneditable-input.span11 {
+    width: 648px;
+  }
+  input.span10,
+  textarea.span10,
+  .uneditable-input.span10 {
+    width: 586px;
+  }
+  input.span9,
+  textarea.span9,
+  .uneditable-input.span9 {
+    width: 524px;
+  }
+  input.span8,
+  textarea.span8,
+  .uneditable-input.span8 {
+    width: 462px;
+  }
+  input.span7,
+  textarea.span7,
+  .uneditable-input.span7 {
+    width: 400px;
+  }
+  input.span6,
+  textarea.span6,
+  .uneditable-input.span6 {
+    width: 338px;
+  }
+  input.span5,
+  textarea.span5,
+  .uneditable-input.span5 {
+    width: 276px;
+  }
+  input.span4,
+  textarea.span4,
+  .uneditable-input.span4 {
+    width: 214px;
+  }
+  input.span3,
+  textarea.span3,
+  .uneditable-input.span3 {
+    width: 152px;
+  }
+  input.span2,
+  textarea.span2,
+  .uneditable-input.span2 {
+    width: 90px;
+  }
+  input.span1,
+  textarea.span1,
+  .uneditable-input.span1 {
+    width: 28px;
+  }
+}
+
+@media (max-width: 767px) {
+  body {
+    padding-right: 20px;
+    padding-left: 20px;
+  }
+  .navbar-fixed-top,
+  .navbar-fixed-bottom,
+  .navbar-static-top {
+    margin-right: -20px;
+    margin-left: -20px;
+  }
+  .container-fluid {
+    padding: 0;
+  }
+  .dl-horizontal dt {
+    float: none;
+    width: auto;
+    clear: none;
+    text-align: left;
+  }
+  .dl-horizontal dd {
+    margin-left: 0;
+  }
+  .container {
+    width: auto;
+  }
+  .row-fluid {
+    width: 100%;
+  }
+  .row,
+  .thumbnails {
+    margin-left: 0;
+  }
+  .thumbnails > li {
+    float: none;
+    margin-left: 0;
+  }
+  [class*="span"],
+  .uneditable-input[class*="span"],
+  .row-fluid [class*="span"] {
+    display: block;
+    float: none;
+    width: 100%;
+    margin-left: 0;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .span12,
+  .row-fluid .span12 {
+    width: 100%;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .row-fluid [class*="offset"]:first-child {
+    margin-left: 0;
+  }
+  .input-large,
+  .input-xlarge,
+  .input-xxlarge,
+  input[class*="span"],
+  select[class*="span"],
+  textarea[class*="span"],
+  .uneditable-input {
+    display: block;
+    width: 100%;
+    min-height: 30px;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .input-prepend input,
+  .input-append input,
+  .input-prepend input[class*="span"],
+  .input-append input[class*="span"] {
+    display: inline-block;
+    width: auto;
+  }
+  .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 0;
+  }
+  .modal {
+    position: fixed;
+    top: 20px;
+    right: 20px;
+    left: 20px;
+    width: auto;
+    margin: 0;
+  }
+  .modal.fade {
+    top: -100px;
+  }
+  .modal.fade.in {
+    top: 20px;
+  }
+}
+
+@media (max-width: 480px) {
+  .nav-collapse {
+    -webkit-transform: translate3d(0, 0, 0);
+  }
+  .page-header h1 small {
+    display: block;
+    line-height: 20px;
+  }
+  input[type="checkbox"],
+  input[type="radio"] {
+    border: 1px solid #ccc;
+  }
+  .form-horizontal .control-label {
+    float: none;
+    width: auto;
+    padding-top: 0;
+    text-align: left;
+  }
+  .form-horizontal .controls {
+    margin-left: 0;
+  }
+  .form-horizontal .control-list {
+    padding-top: 0;
+  }
+  .form-horizontal .form-actions {
+    padding-right: 10px;
+    padding-left: 10px;
+  }
+  .media .pull-left,
+  .media .pull-right {
+    display: block;
+    float: none;
+    margin-bottom: 10px;
+  }
+  .media-object {
+    margin-right: 0;
+    margin-left: 0;
+  }
+  .modal {
+    top: 10px;
+    right: 10px;
+    left: 10px;
+  }
+  .modal-header .close {
+    padding: 10px;
+    margin: -10px;
+  }
+  .carousel-caption {
+    position: static;
+  }
+}
+
+@media (max-width: 979px) {
+  body {
+    padding-top: 0;
+  }
+  .navbar-fixed-top,
+  .navbar-fixed-bottom {
+    position: static;
+  }
+  .navbar-fixed-top {
+    margin-bottom: 20px;
+  }
+  .navbar-fixed-bottom {
+    margin-top: 20px;
+  }
+  .navbar-fixed-top .navbar-inner,
+  .navbar-fixed-bottom .navbar-inner {
+    padding: 5px;
+  }
+  .navbar .container {
+    width: auto;
+    padding: 0;
+  }
+  .navbar .brand {
+    padding-right: 10px;
+    padding-left: 10px;
+    margin: 0 0 0 -5px;
+  }
+  .nav-collapse {
+    clear: both;
+  }
+  .nav-collapse .nav {
+    float: none;
+    margin: 0 0 10px;
+  }
+  .nav-collapse .nav > li {
+    float: none;
+  }
+  .nav-collapse .nav > li > a {
+    margin-bottom: 2px;
+  }
+  .nav-collapse .nav > .divider-vertical {
+    display: none;
+  }
+  .nav-collapse .nav .nav-header {
+    color: #777777;
+    text-shadow: none;
+  }
+  .nav-collapse .nav > li > a,
+  .nav-collapse .dropdown-menu a {
+    padding: 9px 15px;
+    font-weight: bold;
+    color: #777777;
+    -webkit-border-radius: 3px;
+       -moz-border-radius: 3px;
+            border-radius: 3px;
+  }
+  .nav-collapse .btn {
+    padding: 4px 10px 4px;
+    font-weight: normal;
+    -webkit-border-radius: 4px;
+       -moz-border-radius: 4px;
+            border-radius: 4px;
+  }
+  .nav-collapse .dropdown-menu li + li a {
+    margin-bottom: 2px;
+  }
+  .nav-collapse .nav > li > a:hover,
+  .nav-collapse .nav > li > a:focus,
+  .nav-collapse .dropdown-menu a:hover,
+  .nav-collapse .dropdown-menu a:focus {
+    background-color: #f2f2f2;
+  }
+  .navbar-inverse .nav-collapse .nav > li > a,
+  .navbar-inverse .nav-collapse .dropdown-menu a {
+    color: #999999;
+  }
+  .navbar-inverse .nav-collapse .nav > li > a:hover,
+  .navbar-inverse .nav-collapse .nav > li > a:focus,
+  .navbar-inverse .nav-collapse .dropdown-menu a:hover,
+  .navbar-inverse .nav-collapse .dropdown-menu a:focus {
+    background-color: #111111;
+  }
+  .nav-collapse.in .btn-group {
+    padding: 0;
+    margin-top: 5px;
+  }
+  .nav-collapse .dropdown-menu {
+    position: static;
+    top: auto;
+    left: auto;
+    display: none;
+    float: none;
+    max-width: none;
+    padding: 0;
+    margin: 0 15px;
+    background-color: transparent;
+    border: none;
+    -webkit-border-radius: 0;
+       -moz-border-radius: 0;
+            border-radius: 0;
+    -webkit-box-shadow: none;
+       -moz-box-shadow: none;
+            box-shadow: none;
+  }
+  .nav-collapse .open > .dropdown-menu {
+    display: block;
+  }
+  .nav-collapse .dropdown-menu:before,
+  .nav-collapse .dropdown-menu:after {
+    display: none;
+  }
+  .nav-collapse .dropdown-menu .divider {
+    display: none;
+  }
+  .nav-collapse .nav > li > .dropdown-menu:before,
+  .nav-collapse .nav > li > .dropdown-menu:after {
+    display: none;
+  }
+  .nav-collapse .navbar-form,
+  .nav-collapse .navbar-search {
+    float: none;
+    padding: 10px 15px;
+    margin: 10px 0;
+    border-top: 1px solid #f2f2f2;
+    border-bottom: 1px solid #f2f2f2;
+    -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+       -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+            box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+  }
+  .navbar-inverse .nav-collapse .navbar-form,
+  .navbar-inverse .nav-collapse .navbar-search {
+    border-top-color: #111111;
+    border-bottom-color: #111111;
+  }
+  .navbar .nav-collapse .nav.pull-right {
+    float: none;
+    margin-left: 0;
+  }
+  .nav-collapse,
+  .nav-collapse.collapse {
+    height: 0;
+    overflow: hidden;
+  }
+  .navbar .btn-navbar {
+    display: block;
+  }
+  .navbar-static .navbar-inner {
+    padding-right: 10px;
+    padding-left: 10px;
+  }
+}
+
+@media (min-width: 980px) {
+  .nav-collapse.collapse {
+    height: auto !important;
+    overflow: visible !important;
+  }
+}

example/example/static/css/bootstrap-responsive.min.css

-.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";}
-.clearfix:after{clear:both;}
-.hidden{display:none;visibility:hidden;}
-@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:18px;} input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} .input-prepend input[class*="span"],.input-append input[class*="span"]{width:auto;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .modal{position:absolute;top:10px;left:10px;right:10px;width:auto;margin:0;}.modal.fade.in{top:auto;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (max-width:767px){.container{width:auto;padding:0 20px;} .row-fluid{width:100%;} .row{margin-left:0;} .row>[class*="span"],.row-fluid>[class*="span"]{float:none;display:block;width:auto;margin:0;}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:20px;} .span1{width:42px;} .span2{width:104px;} .span3{width:166px;} .span4{width:228px;} .span5{width:290px;} .span6{width:352px;} .span7{width:414px;} .span8{width:476px;} .span9{width:538px;} .span10{width:600px;} .span11{width:662px;} .span12,.container{width:724px;} .offset1{margin-left:82px;} .offset2{margin-left:144px;} .offset3{margin-left:206px;} .offset4{margin-left:268px;} .offset5{margin-left:330px;} .offset6{margin-left:392px;} .offset7{margin-left:454px;} .offset8{margin-left:516px;} .offset9{margin-left:578px;} .offset10{margin-left:640px;} .offset11{margin-left:702px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.762430939%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid>.span1{width:5.801104972%;} .row-fluid>.span2{width:14.364640883%;} .row-fluid>.span3{width:22.928176794%;} .row-fluid>.span4{width:31.491712705%;} .row-fluid>.span5{width:40.055248616%;} .row-fluid>.span6{width:48.618784527%;} .row-fluid>.span7{width:57.182320438000005%;} .row-fluid>.span8{width:65.74585634900001%;} .row-fluid>.span9{width:74.30939226%;} .row-fluid>.span10{width:82.87292817100001%;} .row-fluid>.span11{width:91.436464082%;} .row-fluid>.span12{width:99.999999993%;} input.span1,textarea.span1,.uneditable-input.span1{width:32px;} input.span2,textarea.span2,.uneditable-input.span2{width:94px;} input.span3,textarea.span3,.uneditable-input.span3{width:156px;} input.span4,textarea.span4,.uneditable-input.span4{width:218px;} input.span5,textarea.span5,.uneditable-input.span5{width:280px;} input.span6,textarea.span6,.uneditable-input.span6{width:342px;} input.span7,textarea.span7,.uneditable-input.span7{width:404px;} input.span8,textarea.span8,.uneditable-input.span8{width:466px;} input.span9,textarea.span9,.uneditable-input.span9{width:528px;} input.span10,textarea.span10,.uneditable-input.span10{width:590px;} input.span11,textarea.span11,.uneditable-input.span11{width:652px;} input.span12,textarea.span12,.uneditable-input.span12{width:714px;}}@media (max-width:979px){body{padding-top:0;} .navbar-fixed-top{position:static;margin-bottom:18px;} .navbar-fixed-top .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .navbar .nav-collapse{clear:left;} .navbar .nav{float:none;margin:0 0 9px;} .navbar .nav>li{float:none;} .navbar .nav>li>a{margin-bottom:2px;} .navbar .nav>.divider-vertical{display:none;} .navbar .nav .nav-header{color:#999999;text-shadow:none;} .navbar .nav>li>a,.navbar .dropdown-menu a{padding:6px 15px;font-weight:bold;color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .navbar .dropdown-menu li+li a{margin-bottom:2px;} .navbar .nav>li>a:hover,.navbar .dropdown-menu a:hover{background-color:#222222;} .navbar .dropdown-menu{position:static;top:auto;left:auto;float:none;display:block;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .navbar .dropdown-menu:before,.navbar .dropdown-menu:after{display:none;} .navbar .dropdown-menu .divider{display:none;} .navbar-form,.navbar-search{float:none;padding:9px 15px;margin:9px 0;border-top:1px solid #222222;border-bottom:1px solid #222222;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);} .navbar .nav.pull-right{float:none;margin-left:0;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;} .btn-navbar{display:block;} .nav-collapse{overflow:hidden;height:0;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:30px;} .span1{width:70px;} .span2{width:170px;} .span3{width:270px;} .span4{width:370px;} .span5{width:470px;} .span6{width:570px;} .span7{width:670px;} .span8{width:770px;} .span9{width:870px;} .span10{width:970px;} .span11{width:1070px;} .span12,.container{width:1170px;} .offset1{margin-left:130px;} .offset2{margin-left:230px;} .offset3{margin-left:330px;} .offset4{margin-left:430px;} .offset5{margin-left:530px;} .offset6{margin-left:630px;} .offset7{margin-left:730px;} .offset8{margin-left:830px;} .offset9{margin-left:930px;} .offset10{margin-left:1030px;} .offset11{margin-left:1130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.564102564%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid>.span1{width:5.982905983%;} .row-fluid>.span2{width:14.529914530000001%;} .row-fluid>.span3{width:23.076923077%;} .row-fluid>.span4{width:31.623931624%;} .row-fluid>.span5{width:40.170940171000005%;} .row-fluid>.span6{width:48.717948718%;} .row-fluid>.span7{width:57.264957265%;} .row-fluid>.span8{width:65.81196581200001%;} .row-fluid>.span9{width:74.358974359%;} .row-fluid>.span10{width:82.905982906%;} .row-fluid>.span11{width:91.45299145300001%;} .row-fluid>.span12{width:100%;} input.span1,textarea.span1,.uneditable-input.span1{width:60px;} input.span2,textarea.span2,.uneditable-input.span2{width:160px;} input.span3,textarea.span3,.uneditable-input.span3{width:260px;} input.span4,textarea.span4,.uneditable-input.span4{width:360px;} input.span5,textarea.span5,.uneditable-input.span5{width:460px;} input.span6,textarea.span6,.uneditable-input.span6{width:560px;} input.span7,textarea.span7,.uneditable-input.span7{width:660px;} input.span8,textarea.span8,.uneditable-input.span8{width:760px;} input.span9,textarea.span9,.uneditable-input.span9{width:860px;} input.span10,textarea.span10,.uneditable-input.span10{width:960px;} input.span11,textarea.span11,.uneditable-input.span11{width:1060px;} input.span12,textarea.span12,.uneditable-input.span12{width:1160px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;}}
+/*!
+ * Bootstrap Responsive v2.3.0
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}

example/example/static/css/bootstrap.css

+/*!
+ * Bootstrap v2.3.0
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */