├── .gitignore
├── LICENSE
├── MANIFEST.in
├── README.md
├── better_filter_widget
├── __init__.py
├── models.py
├── static
│ ├── css
│ │ └── better-filter-widget.css
│ └── js
│ │ └── better-filter-widget.js
└── widgets.py
└── setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # C extensions
6 | *.so
7 |
8 | # Distribution / packaging
9 | .Python
10 | env/
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | lib/
17 | lib64/
18 | parts/
19 | sdist/
20 | var/
21 | *.egg-info/
22 | .installed.cfg
23 | *.egg
24 |
25 | # PyInstaller
26 | # Usually these files are written by a python script from a template
27 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
28 | *.manifest
29 | *.spec
30 |
31 | # Installer logs
32 | pip-log.txt
33 | pip-delete-this-directory.txt
34 |
35 | # Unit test / coverage reports
36 | htmlcov/
37 | .tox/
38 | .coverage
39 | .cache
40 | nosetests.xml
41 | coverage.xml
42 |
43 | # Translations
44 | *.mo
45 | *.pot
46 |
47 | # Django stuff:
48 | *.log
49 |
50 | # Sphinx documentation
51 | docs/_build/
52 |
53 | # PyBuilder
54 | target/
55 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Exotic Objects
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 | include LICENSE
3 | recursive-include better_filter_widget *
4 | global-exclude *pyc
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | django-better-filter-widget
2 | ===========================
3 |
4 | A better filter widget for foreign key relationships that also works on mobile devices. This was initially developed as a drop-in replacement for admin forms. It will work in a normal form but you'll have to include some css/js dependencies. I'll write about how to do that soon.
5 |
6 |
7 |
8 | # About
9 | Django's [horizontal and vertical filter widget](http://i.imgur.com/RBgrm.png) is ugly, confusing to new users and completely broken on mobile devices. **django-better-filter-widget** is not magic and does not do real-time lookups like **django-selectable**. It's simply a nicer UI for filtering a list of things that, most importantly, actual works on mobile devices.
10 |
11 |
12 | # Installation
13 |
14 | Note: This project is brand spanking new and is still being tested. It was developed using django 1.6. It was tested in modern desktop and mobile browsers.
15 |
16 | **Install with pip**
17 |
18 | `pip install django-better-filter-widget`
19 |
20 | **settings.py**
21 |
22 | Add 'better_filter_widget' to INSTALLED_APPS in your settings.py
23 |
24 | **admin.py**
25 |
26 | Specify BetterFilterWidget as the widget for your field:
27 |
28 | from django import forms
29 | from django.contrib import admin
30 | from better_filter_widget import BetterFilterWidget
31 |
32 | class MyModelForm(forms.ModelForm):
33 |
34 | class Meta(object):
35 | model = MyModel
36 | widgets = {
37 | 'my_field': BetterFilterWidget(),
38 | }
39 |
40 |
41 | class MyModelAdmin(admin.ModelAdmin):
42 |
43 | form = MyModelForm
44 |
45 | admin.site.register(MyModel, MyModelAdmin)
46 |
47 |
48 | # License
49 |
50 | The MIT License (MIT)
51 |
52 | Copyright (c) 2014 Exotic Objects
53 |
54 | Permission is hereby granted, free of charge, to any person obtaining a copy
55 | of this software and associated documentation files (the "Software"), to deal
56 | in the Software without restriction, including without limitation the rights
57 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
58 | copies of the Software, and to permit persons to whom the Software is
59 | furnished to do so, subject to the following conditions:
60 |
61 | The above copyright notice and this permission notice shall be included in all
62 | copies or substantial portions of the Software.
63 |
64 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
66 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
67 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
68 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
69 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
70 | SOFTWARE.
71 |
72 |
--------------------------------------------------------------------------------
/better_filter_widget/__init__.py:
--------------------------------------------------------------------------------
1 | from .widgets import BetterFilterWidget
--------------------------------------------------------------------------------
/better_filter_widget/models.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExoticObjects/django-better-filter-widget/a9f81df0493c1ba1422fd6f8552e3be227f69e14/better_filter_widget/models.py
--------------------------------------------------------------------------------
/better_filter_widget/static/css/better-filter-widget.css:
--------------------------------------------------------------------------------
1 | .bfw { font-size: 14px; float: left; }
2 | .bfw * { box-sizing: border-box; }
3 | .bfw .title { float: left; width: 220px; font-size: 1.1em; color: #888; font-weight: bold; text-transform: capitalize; }
4 | .bfw input.item-filter { display:block; width: 200px; font-size: 1.5em; height: 40px; padding: 0 10px; background: #eee; border-radius: 0; margin-bottom: 0; }
5 | .bfw .item-list { overflow: auto; float: left; width: 200px; height: 185px; font-size: 1.5em; border: 1px solid #ccc; }
6 | .bfw .selected-items { position: relative; top: -40px; height: 225px;}
7 | .bfw .item-list { float: left; font-size: 1.5em; margin-right: 20px;}
8 | .bfw .item-list .item { display: block; padding: 5px 10px; border-bottom: 1px solid #ddd; cursor: pointer; }
9 | .bfw .item-list .item.selected { display: none; }
10 | .bfw .item-list.available-items .item:active { background: lightgreen; }
11 | .bfw .item-list .glyphicon { float: right; font-size: .9em; line-height: 1.5em; }
12 | .bfw .action-icon { float: right; border-radius: 30px; display: inline-block; width: 20px; height: 20px; color: white; text-align: center; }
13 | .bfw .action-icon-plus { color: lightgreen; }
14 | .bfw .action-icon-minus { color: pink; }
15 | .bfw .item-list.selected-items { height: auto; overflow: visible; }
16 | .bfw .item-list.selected-items .item:active { background: pink; color: white; }
17 | .bf-toast { position: fixed; z-index:10000; top: 5%; left: 45%; text-align: center; background: rgba(0,0,0,.8); border: 1px solid #888; color: white; padding: 1em; border-radius: 3px; display: none; }
--------------------------------------------------------------------------------
/better_filter_widget/static/js/better-filter-widget.js:
--------------------------------------------------------------------------------
1 | function BetterFilterWidget(field_name){
2 |
3 | function updateSelectedDisplay(){
4 | // BFWTimer.start(arguments.callee.name);
5 | selected_items.html('');
6 | orig_input.find('option[selected]').each(function(i, opt){
7 | opt = $(opt);
8 | var item = $('