From a11d9cdfa0f96143ba7df3ca621caa5cc5d4447c Mon Sep 17 00:00:00 2001 From: Artur Barseghyan Date: Fri, 21 Oct 2016 00:19:59 +0200 Subject: [PATCH] prepare 0.8.6; functional improvements of the slider plugin; --- CHANGELOG.rst | 6 ++ TODOS.rst | 4 +- examples/simple/admin_tools_dashboard/conf.py | 5 +- .../commands/clear_dashboard_preferences.py | 11 +- examples/simple/admin_tools_dashboard/menu.py | 24 ++--- examples/simple/bar/admin.py | 2 + examples/simple/bar/models.py | 15 ++- examples/simple/context_processors.py | 7 +- examples/simple/customauth/admin.py | 61 +++++++---- examples/simple/customauth/models.py | 5 + examples/simple/foo/README.rst | 8 +- examples/simple/foo/fobi_form_callbacks.py | 38 ++++--- .../commands/fobi_create_test_data.py | 14 ++- examples/simple/foo/models.py | 7 +- examples/simple/foo/urls.py | 8 +- examples/simple/foo/views.py | 43 +++++--- .../admin.py | 14 +-- .../models.py | 22 ++-- .../fobi_form_elements.py | 22 ++-- .../simple/override_radio_plugin/forms.py | 102 ++++++++++-------- .../fobi_form_elements.py | 25 ++--- .../forms.py | 68 +++++++----- .../override_simple_theme/fobi_themes.py | 13 +-- examples/simple/page/models.py | 5 +- examples/simple/urls.py | 2 +- setup.py | 2 +- src/fobi/__init__.py | 4 +- src/fobi/base.py | 2 +- .../form_elements/fields/slider/constants.py | 38 +++++++ .../fields/slider/fobi_form_elements.py | 82 +++++++++++--- .../form_elements/fields/slider/forms.py | 85 +++++++++++++++ .../fobi.plugin.slider-bootstrap3-widget.css | 10 +- .../fobi.plugin.slider-bootstrap3-widget.js | 1 + 33 files changed, 534 insertions(+), 221 deletions(-) create mode 100644 src/fobi/contrib/plugins/form_elements/fields/slider/constants.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e573d00f..ee2a964d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,12 @@ are used for versioning (schema follows below): 0.3.4 to 0.4). - All backwards incompatible changes are mentioned in this document. +0.8.6 +----- +2016-10-21 + +- Functional improvements of `slider` plugin. + 0.8.5 ----- 2016-10-20 diff --git a/TODOS.rst b/TODOS.rst index 0f66bc16..a60e1e2b 100644 --- a/TODOS.rst +++ b/TODOS.rst @@ -30,12 +30,14 @@ Regarding the form wizards + Make sure to include django-formtools package in the requirements. + Add navigation buttons to the form wizards. - Make sure plugin media is collected in wizards. -- Add data-slider-tooltip="hide" option to the `slider`. ++ Add data-slider-tooltip="hide" option to the `slider`. - Ideally, it would be great to support data-slider-handle="square" (or "round", "triangle") options of the bootstrap-slider plugin. See the first issue in "Uncategorised". - Rethink the new navigation of forms and form wizards. - Add support for form wizard conditions. +- Fixed broken dependencies for docs. +- Fixed non-collected media in the form wizard. Roadmap ------- diff --git a/examples/simple/admin_tools_dashboard/conf.py b/examples/simple/admin_tools_dashboard/conf.py index 16b498b7..780111a7 100644 --- a/examples/simple/admin_tools_dashboard/conf.py +++ b/examples/simple/admin_tools_dashboard/conf.py @@ -13,8 +13,9 @@ fobi_plugins = [ ] fobi_forms = [ - 'fobi.models.FormWizardEntry', 'fobi.models.FormEntry', 'fobi.models.FormElementEntry', - 'fobi.models.FormFieldsetEntry', 'fobi.models.FormHandlerEntry', + 'fobi.models.FormWizardEntry', 'fobi.models.FormEntry', + 'fobi.models.FormElementEntry', 'fobi.models.FormFieldsetEntry', + 'fobi.models.FormHandlerEntry', ] fobi_data = [ diff --git a/examples/simple/admin_tools_dashboard/management/commands/clear_dashboard_preferences.py b/examples/simple/admin_tools_dashboard/management/commands/clear_dashboard_preferences.py index 22ef505b..e3f98c67 100644 --- a/examples/simple/admin_tools_dashboard/management/commands/clear_dashboard_preferences.py +++ b/examples/simple/admin_tools_dashboard/management/commands/clear_dashboard_preferences.py @@ -2,9 +2,14 @@ from django.core.management import BaseCommand from admin_tools.dashboard.models import DashboardPreferences +__all__ = ('Command',) + + class Command(BaseCommand): - help = """ - Clears dashboard preferences. - """ + """Clears dashboard preferences.""" + + help = """Clears dashboard preferences.""" + def handle(self, *args, **options): + """Handle.""" DashboardPreferences._default_manager.all().delete() diff --git a/examples/simple/admin_tools_dashboard/menu.py b/examples/simple/admin_tools_dashboard/menu.py index 096a698e..3a7e268c 100644 --- a/examples/simple/admin_tools_dashboard/menu.py +++ b/examples/simple/admin_tools_dashboard/menu.py @@ -12,12 +12,14 @@ from django.utils.translation import ugettext_lazy as _ from admin_tools.menu import items, Menu -from admin_tools_dashboard import conf +from . import conf + +__all__ = ('CustomMenu',) + class CustomMenu(Menu): - """ - Custom Menu. - """ + """Custom Menu.""" + def __init__(self, **kwargs): Menu.__init__(self, **kwargs) self.children += [ @@ -26,13 +28,13 @@ class CustomMenu(Menu): # Foo self.children.append(items.ModelList(_('Foo'), - models = conf.foo_apps + models=conf.foo_apps )) # Fobi self.children.append(items.MenuItem( _('Fobi'), - children = [ + children=[ items.ModelList(_('Plugins'), models=conf.fobi_plugins), items.ModelList(_('Forms'), models=conf.fobi_forms), items.ModelList(_('Data'), models=conf.fobi_data), @@ -43,24 +45,22 @@ class CustomMenu(Menu): # FeinCMS pages integration self.children.append(items.AppList( _('FeinCMS Pages'), - models = conf.feincms_pages + models=conf.feincms_pages )) if 'cms' in settings.INSTALLED_APPS: # DjangoCMS pages integration self.children.append(items.AppList( _('DjangoCMS Pages'), - models = conf.djangocms_pages + models=conf.djangocms_pages )) # append an app list module for "Administration" self.children.append(items.AppList( _('Administration'), - models = ['django.contrib.*',] + models=['django.contrib.*',] )) def init_with_context(self, context): - """ - Use this method if you need to access the request context. - """ + """Use this method if you need to access the request context.""" return super(CustomMenu, self).init_with_context(context) diff --git a/examples/simple/bar/admin.py b/examples/simple/bar/admin.py index 5157f696..a014062a 100644 --- a/examples/simple/bar/admin.py +++ b/examples/simple/bar/admin.py @@ -1,5 +1,7 @@ from django.contrib import admin + from mptt.admin import MPTTModelAdmin + from .models import Genre admin.site.register(Genre, MPTTModelAdmin) diff --git a/examples/simple/bar/models.py b/examples/simple/bar/models.py index a65fedb2..c509b8db 100644 --- a/examples/simple/bar/models.py +++ b/examples/simple/bar/models.py @@ -1,14 +1,25 @@ +from six import python_2_unicode_compatible + from django.db import models + from mptt.models import MPTTModel, TreeForeignKey +__all__ = ('Genre',) + + +@python_2_unicode_compatible class Genre(MPTTModel): + """Genre.""" + name = models.CharField(max_length=50, unique=True) parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True) class MPTTMeta: - #level_attr = 'mptt_level' + """MPTT meta.""" + + # level_attr = 'mptt_level' order_insertion_by=['name'] - def __unicode__(self): + def __str__(self): return self.name diff --git a/examples/simple/context_processors.py b/examples/simple/context_processors.py index 504f59b7..0e0620ba 100644 --- a/examples/simple/context_processors.py +++ b/examples/simple/context_processors.py @@ -1,5 +1,6 @@ +__all__ = ('disable_admin_tools',) + + def disable_admin_tools(request): - """ - Disable admin tools. - """ + """Disable admin tools.""" return {'ADMIN_TOOLS_DISABLED': True} diff --git a/examples/simple/customauth/admin.py b/examples/simple/customauth/admin.py index 24e61930..7f7f74e3 100644 --- a/examples/simple/customauth/admin.py +++ b/examples/simple/customauth/admin.py @@ -4,18 +4,32 @@ from django.contrib.auth.models import Group from django.contrib.auth.admin import UserAdmin from django.contrib.auth.forms import ReadOnlyPasswordHashField -from customauth.models import MyUser +from .models import MyUser + +__all__ = ( + 'UserCreationForm', + 'UserChangeForm', + 'MyUserAdmin', +) class UserCreationForm(forms.ModelForm): - """A form for creating new users. Includes all the required - fields, plus a repeated password.""" - password1 = forms.CharField(label='Password', widget=forms.PasswordInput) - password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput) + """A form for creating new users. + + Includes all the required fields, plus a repeated password. + """ + + password1 = forms.CharField(label='Password', + widget=forms.PasswordInput) + password2 = forms.CharField(label='Password confirmation', + widget=forms.PasswordInput) class Meta: + """Meta.""" + model = MyUser - fields = ('username', 'email', 'first_name', 'last_name', 'date_of_birth') + fields = ('username', 'email', 'first_name', 'last_name', + 'date_of_birth',) def clean_password2(self): # Check that the two password entries match @@ -35,15 +49,20 @@ class UserCreationForm(forms.ModelForm): class UserChangeForm(forms.ModelForm): - """A form for updating users. Includes all the fields on - the user, but replaces the password field with admin's - password hash display field. + """A form for updating users. + + Includes all the fields on the user, but replaces the password field + with admin's password hash display field. """ + password = ReadOnlyPasswordHashField() class Meta: + """Meta.""" + model = MyUser - fields = ('username', 'email', 'first_name', 'last_name', 'password', 'date_of_birth', 'is_active',) + fields = ('username', 'email', 'first_name', 'last_name', 'password', + 'date_of_birth', 'is_active',) def clean_password(self): # Regardless of what the user provides, return the initial value. @@ -53,6 +72,8 @@ class UserChangeForm(forms.ModelForm): class MyUserAdmin(UserAdmin): + """MyUser admin.""" + # The forms to add and change user instances form = UserChangeForm add_form = UserCreationForm @@ -60,10 +81,12 @@ class MyUserAdmin(UserAdmin): # The fields to be used in displaying the User model. # These override the definitions on the base UserAdmin # that reference specific fields on auth.User. - list_display = ('username', 'email', 'first_name', 'last_name', 'date_of_birth',) + list_display = ('username', 'email', 'first_name', 'last_name', + 'date_of_birth',) fieldsets = ( (None, {'fields': ('username', 'email', 'password')}), - ('Personal info', {'fields': ('first_name', 'last_name', 'date_of_birth',)}), + ('Personal info', {'fields': ('first_name', 'last_name', + 'date_of_birth',)}), ('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}), ) @@ -72,16 +95,18 @@ class MyUserAdmin(UserAdmin): add_fieldsets = ( (None, { 'classes': ('wide',), - 'fields': ('username', 'email', 'first_name', 'last_name', 'date_of_birth', - 'password1', 'password2')} - ), + 'fields': ('username', 'email', 'first_name', 'last_name', + 'date_of_birth', 'password1', 'password2')} + ) ) search_fields = ('email',) ordering = ('email',) - filter_horizontal = () + filter_horizontal = [] + # Now register the new UserAdmin... admin.site.register(MyUser, MyUserAdmin) -# ... and, since we're not using Django's built-in permissions, -# unregister the Group model from admin. + +# ...and, since we're not using Django's built-in permissions, +# un-register the Group model from admin. admin.site.unregister(Group) diff --git a/examples/simple/customauth/models.py b/examples/simple/customauth/models.py index ab6f0c61..ebd93f22 100644 --- a/examples/simple/customauth/models.py +++ b/examples/simple/customauth/models.py @@ -1,5 +1,10 @@ from django.db import models from django.contrib.auth.models import AbstractUser +__all__ = ('MyUser',) + + class MyUser(AbstractUser): + """My user.""" + date_of_birth = models.DateField(null=True, blank=True) diff --git a/examples/simple/foo/README.rst b/examples/simple/foo/README.rst index 1fb3f1fe..a24c6447 100644 --- a/examples/simple/foo/README.rst +++ b/examples/simple/foo/README.rst @@ -1,7 +1,7 @@ -===================================== -Example app -===================================== -Gemeral purpose example app that: +=== +foo +=== +A general purpose example app that: - Shows how to make a form callback. - Contains a sample endpoint for testing the HTTP repost form handler plugin. diff --git a/examples/simple/foo/fobi_form_callbacks.py b/examples/simple/foo/fobi_form_callbacks.py index 00264a7e..1e09b81e 100644 --- a/examples/simple/foo/fobi_form_callbacks.py +++ b/examples/simple/foo/fobi_form_callbacks.py @@ -2,28 +2,34 @@ from __future__ import print_function import logging +from fobi.base import FormCallback, form_callback_registry +from fobi.constants import ( + CALLBACK_BEFORE_FORM_VALIDATION, + CALLBACK_FORM_VALID_BEFORE_SUBMIT_PLUGIN_FORM_DATA, + CALLBACK_FORM_VALID, + CALLBACK_FORM_VALID_AFTER_FORM_HANDLERS, + CALLBACK_FORM_INVALID +) + logger = logging.getLogger('fobi') -from fobi.constants import ( - CALLBACK_BEFORE_FORM_VALIDATION, CALLBACK_FORM_VALID_BEFORE_SUBMIT_PLUGIN_FORM_DATA, - CALLBACK_FORM_VALID, CALLBACK_FORM_VALID_AFTER_FORM_HANDLERS, CALLBACK_FORM_INVALID - ) -from fobi.base import FormCallback, form_callback_registry +__all__= ( + 'SaveAsFooItem', + 'DummyInvalidCallback', +) # ************************************************************* # **************** Save as foo callback *********************** # ************************************************************* + class SaveAsFooItem(FormCallback): - """ - Saves the form as a foo item, if certain conditions are met. - """ + """Save the form as a foo item, if certain conditions are met.""" + stage = CALLBACK_FORM_VALID def callback(self, form_entry, request, form): - """ - Custom callback login comes here. - """ + """Custom callback login comes here.""" logger.debug("Great! Your form is valid!") @@ -33,16 +39,14 @@ form_callback_registry.register(SaveAsFooItem) # **************** Save as foo callback *********************** # ************************************************************* + class DummyInvalidCallback(FormCallback): - """ - Saves the form as a foo item, if certain conditions are met. - """ + """Saves the form as a foo item, if certain conditions are met.""" + stage = CALLBACK_FORM_INVALID def callback(self, form_entry, request, form): - """ - Custom callback login comes here. - """ + """Custom callback login comes here.""" logger.debug("Damn! You've made a mistake, boy!") diff --git a/examples/simple/foo/management/commands/fobi_create_test_data.py b/examples/simple/foo/management/commands/fobi_create_test_data.py index ead6c776..ce3391b0 100644 --- a/examples/simple/foo/management/commands/fobi_create_test_data.py +++ b/examples/simple/foo/management/commands/fobi_create_test_data.py @@ -1,16 +1,20 @@ from django.core.management.base import BaseCommand from fobi.tests.helpers import ( - get_or_create_admin_user, create_form_with_entries + get_or_create_admin_user, + create_form_with_entries ) +__all__ = ('Command',) + + class Command(BaseCommand): + """Creates test data to fill the dashboard with.""" + def handle(self, *args, **options): - """ - Creates test data to fill the dashboard with. - """ + """Handle.""" try: user = get_or_create_admin_user() create_form_with_entries(user, create_entries_if_form_exist=False) - except Exception as e: + except Exception as err: pass diff --git a/examples/simple/foo/models.py b/examples/simple/foo/models.py index 38af0f40..f0747194 100644 --- a/examples/simple/foo/models.py +++ b/examples/simple/foo/models.py @@ -1,4 +1,9 @@ from django.db import models +__all__ = ('FileTest',) + + class FileTest(models.Model): - file = models.FileField(upload_to='foo/') \ No newline at end of file + """File test.""" + + file = models.FileField(upload_to='foo/') diff --git a/examples/simple/foo/urls.py b/examples/simple/foo/urls.py index 475883d4..767366cd 100644 --- a/examples/simple/foo/urls.py +++ b/examples/simple/foo/urls.py @@ -1,9 +1,13 @@ from django.conf.urls import url -from foo.views import ( - endpoint as foo_views_endpoint, forms_list as foo_forms_list, +from .views import ( + endpoint as foo_views_endpoint, + forms_list as foo_forms_list ) +__all__ = ('urlpatterns',) + + urlpatterns = [ url(r'^endpoint/$', view=foo_views_endpoint, name='foo.endpoint'), url(r'^forms-list/$', view=foo_forms_list, name='foo.forms_list'), diff --git a/examples/simple/foo/views.py b/examples/simple/foo/views.py index 671b5c34..3346f07e 100644 --- a/examples/simple/foo/views.py +++ b/examples/simple/foo/views.py @@ -1,24 +1,34 @@ -import uuid import logging +import uuid from django.http import HttpResponse -from django.views.decorators.csrf import csrf_exempt from django.template import RequestContext -from django.shortcuts import render_to_response +from django.views.decorators.csrf import csrf_exempt -from fobi.models import FormEntry -from fobi.helpers import handle_uploaded_file from fobi.base import get_theme +from fobi.helpers import handle_uploaded_file +from fobi.models import FormEntry + +from nine import versions + +if versions.DJANGO_GTE_1_10: + from django.shortcuts import render +else: + from django.shortcuts import render_to_response logger = logging.getLogger('fobi') +__all__ = ( + 'endpoint', + 'forms_list', +) + + @csrf_exempt def endpoint(request): - """ - Endpoint. + """Endpoint. :param django.http.HttpRequest request: - :param string template_name: :return django.http.HttpResponse: """ logger.debug("POST: {0}\nFILES: {1}".format(request.POST, request.FILES)) @@ -32,8 +42,11 @@ def endpoint(request): def forms_list(request, template_name='foo/forms_list.html'): - """ - Fobi forms list. + """Fobi forms list. + + :param django.http.HttpRequest request: + :param string template_name: + :return django.http.HttpResponse: """ form_entries = FormEntry._default_manager.filter(is_public=True) \ .select_related('user') @@ -46,6 +59,10 @@ def forms_list(request, template_name='foo/forms_list.html'): 'show_delete_link': False, 'show_export_link': False, } - return render_to_response( - template_name, context, context_instance=RequestContext(request) - ) + + if versions.DJANGO_GTE_1_10: + return render(request, template_name, context) + else: + return render_to_response( + template_name, context, context_instance=RequestContext(request) + ) diff --git a/examples/simple/foreign_key_to_saved_form_data_entry/admin.py b/examples/simple/foreign_key_to_saved_form_data_entry/admin.py index 41b7dd7d..b3c0bb25 100644 --- a/examples/simple/foreign_key_to_saved_form_data_entry/admin.py +++ b/examples/simple/foreign_key_to_saved_form_data_entry/admin.py @@ -1,11 +1,10 @@ -__all__ = ('SavedFormDataEntryReferenceAdmin',) - from django.contrib import admin from django.utils.translation import ugettext_lazy as _ -from foreign_key_to_saved_form_data_entry.models import ( - SavedFormDataEntryReference - ) +from .models import SavedFormDataEntryReference + +__all__ = ('SavedFormDataEntryReferenceAdmin',) + class SavedFormDataEntryReferenceAdmin(admin.ModelAdmin): list_display = ('form',) @@ -14,5 +13,6 @@ class SavedFormDataEntryReferenceAdmin(admin.ModelAdmin): app_label = _('ForeignKey to db_store.SavedFormDataEntry') -admin.site.register(SavedFormDataEntryReference, - SavedFormDataEntryReferenceAdmin) +admin.site.register( + SavedFormDataEntryReference, SavedFormDataEntryReferenceAdmin +) diff --git a/examples/simple/foreign_key_to_saved_form_data_entry/models.py b/examples/simple/foreign_key_to_saved_form_data_entry/models.py index 4335ecba..161b2daf 100644 --- a/examples/simple/foreign_key_to_saved_form_data_entry/models.py +++ b/examples/simple/foreign_key_to_saved_form_data_entry/models.py @@ -1,15 +1,21 @@ -__all__ = ('SavedFormDataEntryReference',) +from six import python_2_unicode_compatible from django.db import models -#from fobi.contrib.plugins.form_handlers.db_store.models import ( -# SavedFormDataEntry -# ) +__all__ = ('SavedFormDataEntryReference',) + +@python_2_unicode_compatible class SavedFormDataEntryReference(models.Model): - """ - Model which references the + """SavedFormDataEntryReference model. + + References the `fobi.contrib.plugins.form_handlers.db_store.models.SavedFormDataEntry`. """ - #form = models.ForeignKey(SavedFormDataEntry) - form = models.ForeignKey('fobi_contrib_plugins_form_handlers_db_store.SavedFormDataEntry') + + form = models.ForeignKey( + 'fobi_contrib_plugins_form_handlers_db_store.SavedFormDataEntry' + ) + + def __str__(self): + return self.form.name diff --git a/examples/simple/override_radio_plugin/fobi_form_elements.py b/examples/simple/override_radio_plugin/fobi_form_elements.py index 901e66ea..aef17dd0 100644 --- a/examples/simple/override_radio_plugin/fobi_form_elements.py +++ b/examples/simple/override_radio_plugin/fobi_form_elements.py @@ -1,30 +1,28 @@ -__all__ = ('RadioInputPlugin',) - from django.forms.fields import ChoiceField from django.forms.widgets import RadioSelect from django.utils.translation import ugettext_lazy as _ from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.helpers import safe_text, get_select_field_choices from fobi.contrib.plugins.form_elements.fields.radio import UID +from fobi.helpers import safe_text, get_select_field_choices -from override_radio_plugin.forms import RadioInputForm +from .forms import RadioInputForm theme = get_theme(request=None, as_instance=True) +__all__ = ('RadioInputPlugin',) + + class RadioInputPlugin(FormFieldPlugin): - """ - Radio field plugin. - """ + """Radio field plugin.""" + uid = UID name = _("Radio") group = _("Fields") form = RadioInputForm def get_form_field_instances(self, request=None): - """ - Get form field instances. - """ + """Get form field instances.""" choices = get_select_field_choices(self.data.choices) widget_attrs = {'class': theme.form_radio_element_html_class} @@ -40,8 +38,7 @@ class RadioInputPlugin(FormFieldPlugin): return [(self.data.name, ChoiceField, kwargs)] def submit_plugin_form_data(self, form_entry, request, form): - """ - Submit plugin form data/process. + """Submit plugin form data/process. :param fobi.models.FormEntry form_entry: Instance of ``fobi.models.FormEntry``. @@ -63,4 +60,5 @@ class RadioInputPlugin(FormFieldPlugin): # ``cleaned_data`` return form + form_element_plugin_registry.register(RadioInputPlugin, force=True) diff --git a/examples/simple/override_radio_plugin/forms.py b/examples/simple/override_radio_plugin/forms.py index 62cd7ab7..4f848a9e 100644 --- a/examples/simple/override_radio_plugin/forms.py +++ b/examples/simple/override_radio_plugin/forms.py @@ -1,5 +1,3 @@ -__all__ = ('RadioInputForm',) - from django import forms from django.utils.translation import ugettext_lazy as _ @@ -8,10 +6,12 @@ from fobi.helpers import validate_initial_for_choices theme = get_theme(request=None, as_instance=True) +__all__ = ('RadioInputForm',) + + class RadioInputForm(forms.Form, BaseFormFieldPluginForm): - """ - Form for ``RadioInputPlugin``. - """ + """Form for ``RadioInputPlugin``.""" + plugin_data_fields = [ ("label", ""), ("name", ""), @@ -22,54 +22,72 @@ class RadioInputForm(forms.Form, BaseFormFieldPluginForm): ] label = forms.CharField( - label = _("Label"), - required = True, - widget = forms.widgets.TextInput(attrs={'class': theme.form_element_html_class}) + label=_("Label"), + required=True, + widget=forms.widgets.TextInput( + attrs={'class': theme.form_element_html_class} ) + ) name = forms.CharField( - label = _("Name"), - required = True, - widget = forms.widgets.TextInput(attrs={'class': theme.form_element_html_class}) + label=_("Name"), + required=True, + widget=forms.widgets.TextInput( + attrs={'class': theme.form_element_html_class} ) + ) choices = forms.CharField( - label = _("Choices"), - required = False, - help_text = _("Enter single values/pairs per line. Example:
" - "    1
" - "    2
" - "    alpha, Alpha
" - "    beta, Beta
" - "    omega" - "

" - "It finally transforms into the following HTML code:
" - '    <select id="id_NAME_OF_THE_ELEMENT" name="NAME_OF_THE_ELEMENT">
' - '        <option value="1">1</option>
' - '        <option value="2">2</option>
' - '        <option value="alpha">Alpha</option>
' - '        <option value="beta">Beta</option>
' - '        <option value="omega">omega</option>
' - '    </select>' - "
"), - widget = forms.widgets.Textarea(attrs={'class': theme.form_element_html_class}) + label=_("Choices"), + required=False, + help_text=_("Enter single values/pairs per line. Example:
" + "    1
" + "    2
" + "    alpha, Alpha
" + "    beta, Beta
" + "    omega" + "

" + "It finally transforms into the following HTML code:" + "
" + '    <select ' + 'id="id_NAME_OF_THE_ELEMENT" ' + 'name="NAME_OF_THE_ELEMENT">
' + '        ' + '<option value="1">1</option>
' + '        ' + '<option value="2">2</option>
' + '        ' + '<option value="alpha">Alpha</option>
' + '        ' + '<option value="beta">Beta</option>
' + '        ' + '<option value="omega">omega</option>
' + '    </select>' + "
"), + widget=forms.widgets.Textarea( + attrs={'class': theme.form_element_html_class} ) + ) help_text = forms.CharField( - label = _("Help text"), - required = False, - widget = forms.widgets.Textarea(attrs={'class': theme.form_element_html_class}) + label=_("Help text"), + required=False, + widget=forms.widgets.Textarea( + attrs={'class': theme.form_element_html_class} ) + ) initial = forms.CharField( - label = _("Initial"), - required = False, - widget = forms.widgets.TextInput(attrs={'class': theme.form_element_html_class}) + label=_("Initial"), + required=False, + widget=forms.widgets.TextInput( + attrs={'class': theme.form_element_html_class} ) + ) required = forms.BooleanField( - label = _("Required"), - required = False, - widget = forms.widgets.CheckboxInput(attrs={'class': theme.form_element_checkbox_html_class}) + label=_("Required"), + required=False, + widget=forms.widgets.CheckboxInput( + attrs={'class': theme.form_element_checkbox_html_class} ) + ) def clean_initial(self): - """ - Validating the initial value. - """ + """Validating the initial value.""" return validate_initial_for_choices(self, 'choices', 'initial') diff --git a/examples/simple/override_select_model_object_plugin/fobi_form_elements.py b/examples/simple/override_select_model_object_plugin/fobi_form_elements.py index dedd9b8e..93a48f71 100644 --- a/examples/simple/override_select_model_object_plugin/fobi_form_elements.py +++ b/examples/simple/override_select_model_object_plugin/fobi_form_elements.py @@ -4,26 +4,26 @@ from django.forms.widgets import Select from django.utils.translation import ugettext_lazy as _ from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme -from fobi.helpers import safe_text from fobi.contrib.plugins.form_elements.fields.select_model_object import UID -from override_select_model_object_plugin.forms \ - import SelectModelObjectInputForm +from fobi.helpers import safe_text + +from .forms import SelectModelObjectInputForm theme = get_theme(request=None, as_instance=True) +__all__ = ('SelectModelObjectInputPlugin',) + + class SelectModelObjectInputPlugin(FormFieldPlugin): - """ - Select model object field plugin. - """ + """Select model object field plugin.""" + uid = UID name = _("Select model object") group = _("Fields") form = SelectModelObjectInputForm def get_form_field_instances(self, request=None): - """ - Get form field instances. - """ + """Get form field instances.""" app_label, model_name = self.data.model.split('.') model = models.get_model(app_label, model_name) queryset = model._default_manager.all() @@ -40,8 +40,7 @@ class SelectModelObjectInputPlugin(FormFieldPlugin): return [(self.data.name, ModelChoiceField, kwargs)] def submit_plugin_form_data(self, form_entry, request, form): - """ - Submit plugin form data/process. + """Submit plugin form data/process. :param fobi.models.FormEntry form_entry: Instance of ``fobi.models.FormEntry``. @@ -52,9 +51,7 @@ class SelectModelObjectInputPlugin(FormFieldPlugin): obj = form.cleaned_data.get(self.data.name, None) if obj: # Handle the submitted form value - value = '{0}'.format( - safe_text(obj) - ) + value = '{0}'.format(safe_text(obj)) # Overwrite ``cleaned_data`` of the ``form`` with object qualifier. form.cleaned_data[self.data.name] = value diff --git a/examples/simple/override_select_model_object_plugin/forms.py b/examples/simple/override_select_model_object_plugin/forms.py index 01ac9fa8..f548c523 100644 --- a/examples/simple/override_select_model_object_plugin/forms.py +++ b/examples/simple/override_select_model_object_plugin/forms.py @@ -1,5 +1,3 @@ -__all__ = ('SelectModelObjectInputForm',) - from django import forms from django.utils.translation import ugettext_lazy as _ @@ -10,10 +8,12 @@ from fobi.contrib.plugins.form_elements.fields.select_model_object.settings \ theme = get_theme(request=None, as_instance=True) +__all__ = ('SelectModelObjectInputForm',) + + class SelectModelObjectInputForm(forms.Form, BaseFormFieldPluginForm): - """ - Form for ``SelectModelObjectPlugin``. - """ + """Form for ``SelectModelObjectPlugin``.""" + plugin_data_fields = [ ("label", ""), ("name", ""), @@ -24,42 +24,52 @@ class SelectModelObjectInputForm(forms.Form, BaseFormFieldPluginForm): ] label = forms.CharField( - label = _("Label"), - required = True, - widget = forms.widgets.TextInput(attrs={'class': theme.form_element_html_class}) + label=_("Label"), + required=True, + widget=forms.widgets.TextInput( + attrs={'class': theme.form_element_html_class} ) + ) name = forms.CharField( - label = _("Name"), - required = True, - widget = forms.widgets.TextInput(attrs={'class': theme.form_element_html_class}) + label=_("Name"), + required=True, + widget=forms.widgets.TextInput( + attrs={'class': theme.form_element_html_class} ) + ) model = forms.ChoiceField( - label = _("Model"), - choices = [], - required = False, - widget = forms.widgets.Select(attrs={'class': theme.form_element_html_class}) + label=_("Model"), + choices=[], + required=False, + widget=forms.widgets.Select( + attrs={'class': theme.form_element_html_class} ) + ) help_text = forms.CharField( - label = _("Help text"), - required = False, - widget = forms.widgets.Textarea(attrs={'class': theme.form_element_html_class}) + label=_("Help text"), + required=False, + widget=forms.widgets.Textarea( + attrs={'class': theme.form_element_html_class} ) + ) initial = forms.CharField( - label = _("Initial"), - required = False, - widget = forms.widgets.TextInput(attrs={'class': theme.form_element_html_class}) + label=_("Initial"), + required=False, + widget=forms.widgets.TextInput( + attrs={'class': theme.form_element_html_class} ) + ) required = forms.BooleanField( - label = _("Required"), - required = False, - widget = forms.widgets.CheckboxInput(attrs={'class': theme.form_element_checkbox_html_class}) + label=_("Required"), + required=False, + widget=forms.widgets.CheckboxInput( + attrs={'class': theme.form_element_checkbox_html_class} ) + ) def __init__(self, *args, **kwargs): - """ - In order to avoid static calls to `get_registered_models`. - """ + """In order to avoid static calls to `get_registered_models`.""" super(SelectModelObjectInputForm, self).__init__(*args, **kwargs) self.fields['model'].choices = get_registered_models( - ignore = IGNORED_MODELS - ) + ignore=IGNORED_MODELS + ) diff --git a/examples/simple/override_simple_theme/fobi_themes.py b/examples/simple/override_simple_theme/fobi_themes.py index b9ca9d61..752f425a 100644 --- a/examples/simple/override_simple_theme/fobi_themes.py +++ b/examples/simple/override_simple_theme/fobi_themes.py @@ -1,17 +1,18 @@ -__all__ = ('MySimpleTheme',) - from fobi.base import theme_registry from fobi.contrib.themes.simple.fobi_themes import SimpleTheme +__all__ = ('MySimpleTheme',) + + class MySimpleTheme(SimpleTheme): - """ - Overriding the "simple" theme. - """ + """Overriding the "simple" theme.""" + html_classes = ['my-simple-theme',] base_view_template = 'override_simple_theme/base_view.html' form_ajax = 'override_simple_theme/snippets/form_ajax.html' - form_snippet_template_name = 'override_simple_theme/snippets/form_snippet.html' + form_snippet_template_name = \ + 'override_simple_theme/snippets/form_snippet.html' # It's important to set the `force` argument to True, in diff --git a/examples/simple/page/models.py b/examples/simple/page/models.py index f454b5a0..ef8f3560 100644 --- a/examples/simple/page/models.py +++ b/examples/simple/page/models.py @@ -1,8 +1,9 @@ from django.utils.translation import ugettext_lazy as _ -from feincms.module.page.models import Page from feincms.content.raw.models import RawContent from feincms.content.richtext.models import RichTextContent +from feincms.module.page.models import Page + # Import the ``django-fobi`` widget. from fobi.contrib.apps.feincms_integration.widgets import FobiFormWidget @@ -19,7 +20,7 @@ Page.register_templates( ('sidebar', _(u"Sidebar")), ) }, - ) +) # Standard content types Page.create_content_type(RawContent) diff --git a/examples/simple/urls.py b/examples/simple/urls.py index ffaa6b02..43eaf7ac 100644 --- a/examples/simple/urls.py +++ b/examples/simple/urls.py @@ -21,7 +21,7 @@ fobi_theme_home_template_mapping = { fobi_home_template = fobi_theme_home_template_mapping.get( DEFAULT_THEME, 'home/base.html' - ) +) FOBI_EDIT_URLS_PREFIX = '' if DEFAULT_THEME in ('simple', 'djangocms_admin_style_theme'): diff --git a/setup.py b/setup.py index 91c2284f..9049e327 100644 --- a/setup.py +++ b/setup.py @@ -199,7 +199,7 @@ for locale_dir in locale_dirs: for f in os.listdir(locale_dir)] -version = '0.8.5' +version = '0.8.6' install_requires = [] # If certain version of Django is already installed, choose version agnostic diff --git a/src/fobi/__init__.py b/src/fobi/__init__.py index 402f221a..257beac4 100644 --- a/src/fobi/__init__.py +++ b/src/fobi/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-fobi' -__version__ = '0.8.5' -__build__ = 0x00005c +__version__ = '0.8.6' +__build__ = 0x00005d __author__ = 'Artur Barseghyan ' __copyright__ = '2014-2016 Artur Barseghyan' __license__ = 'GPL 2.0/LGPL 2.1' diff --git a/src/fobi/base.py b/src/fobi/base.py index c97f3360..7710be71 100644 --- a/src/fobi/base.py +++ b/src/fobi/base.py @@ -1411,7 +1411,7 @@ class FormElementPlugin(BasePlugin): # fobi specific context processor. By automatically # force-prefixing all dynamic value definitions with # "fobi_dynamic_values." string. See the docs for - # more ("Dyamic initial values" section). + # more ("Dynamic initial values" section). initial = field_kwargs['initial'] # For the moment, only string types are dynamic diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/constants.py b/src/fobi/contrib/plugins/form_elements/fields/slider/constants.py new file mode 100644 index 00000000..e09df339 --- /dev/null +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/constants.py @@ -0,0 +1,38 @@ +from django.utils.translation import ugettext_lazy as _ + +__all__ = ( + 'SLIDER_TOOLTIP_SHOW', + 'SLIDER_TOOLTIP_HIDE', + 'SLIDER_TOOLTIP_ALWAYS', + 'SLIDER_DEFAULT_TOOLTIP', + 'SLIDER_TOOLTIP_CHOICES', + + 'SLIDER_HANDLE_ROUND', + 'SLIDER_HANDLE_SQUARE', + 'SLIDER_HANDLE_TRIANGLE', + 'SLIDER_HANDLE_CUSTOM', + 'SLIDER_HANDLE_CHOICES', +) + +SLIDER_TOOLTIP_SHOW = 'show' +SLIDER_TOOLTIP_HIDE = 'hide' +SLIDER_TOOLTIP_ALWAYS = 'always' +SLIDER_DEFAULT_TOOLTIP = SLIDER_TOOLTIP_HIDE + +SLIDER_TOOLTIP_CHOICES = ( + (SLIDER_TOOLTIP_SHOW, _("Show")), + (SLIDER_TOOLTIP_HIDE, _("Hide")), + (SLIDER_TOOLTIP_ALWAYS, _("Always")), +) + +SLIDER_HANDLE_ROUND = 'round' +SLIDER_HANDLE_SQUARE = 'square' +SLIDER_HANDLE_TRIANGLE = 'triangle' +SLIDER_HANDLE_CUSTOM = 'custom' +SLIDER_DEFAULT_HANDLE = SLIDER_HANDLE_ROUND +SLIDER_HANDLE_CHOICES = ( + (SLIDER_HANDLE_ROUND, _("Round")), + (SLIDER_HANDLE_SQUARE, _("Square")), + (SLIDER_HANDLE_TRIANGLE, _("Triangle")), + (SLIDER_HANDLE_CUSTOM, _("Custom")), +) diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py b/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py index c227f528..8541d2ab 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/fobi_form_elements.py @@ -1,10 +1,12 @@ from django.forms.fields import ChoiceField -from django.forms.widgets import TextInput, Select +from django.forms.widgets import Select from django.utils.translation import ugettext_lazy as _ from fobi.base import FormFieldPlugin, form_element_plugin_registry, get_theme +from fobi.helpers import get_select_field_choices from . import UID +from .constants import SLIDER_DEFAULT_TOOLTIP, SLIDER_DEFAULT_HANDLE from .forms import SliderInputForm from .settings import INITIAL, MAX_VALUE, MIN_VALUE, STEP @@ -33,27 +35,83 @@ class SliderInputPlugin(FormFieldPlugin): max_value = self.data.max_value if self.data.max_value else MAX_VALUE min_value = self.data.min_value if self.data.min_value else MIN_VALUE step = self.data.step if self.data.step else STEP + tooltip = self.data.tooltip \ + if self.data.tooltip \ + else SLIDER_DEFAULT_TOOLTIP + handle = self.data.handle \ + if self.data.handle \ + else SLIDER_DEFAULT_HANDLE + + # custom_ticks = get_select_field_choices(self.data.custom_ticks) \ + # if self.data.custom_ticks \ + # else [] _choices = range(min_value, max_value, step) choices = zip(_choices, _choices) + # slider_html_class = "slider-no-background" \ + # if self.data.disable_slider_background \ + # else "slider" + slider_html_class = "slider" + + widget_attrs = { + 'class': "{0} {1}".format( + slider_html_class, + theme.form_element_html_class + ), + 'data-slider-min': min_value, + 'data-slider-max': max_value, + 'data-slider-step': step, + 'data-slider-tooltip': tooltip, + 'data-slider-handle': handle, + } + + if self.data.enable_ticks: + # if custom_ticks: + # pass + # else: + tick_label_start = self.data.tick_label_start \ + if self.data.tick_label_start \ + else min_value + + tick_label_end = self.data.tick_label_end \ + if self.data.tick_label_end \ + else max_value + + widget_attrs.update({ + 'data-slider-ticks': "[{0}, {1}]".format( + min_value, max_value + ), + 'data-slider-ticks-labels': '["{0}", "{1}"]'.format( + tick_label_start, tick_label_end + ), + }) + + # I hate to do so, but it seems like a dirty workaround that works. + if 'POST' == request.method: + try: + value = int(request.POST.get(self.data.name, initial)) + except (ValueError, TypeError) as err: + value = initial + + if value < min_value or value > max_value: + value = initial + + widget_attrs.update({ + 'data-slider-value': value, + }) + else: + widget_attrs.update({ + 'data-slider-value': initial, + }) + kwargs = { 'label': self.data.label, 'help_text': self.data.help_text, 'initial': initial, 'required': self.data.required, 'choices': choices, - 'widget': Select( - attrs={ - 'class': "slider {0}".format( - theme.form_element_html_class - ), - 'data-slider-min': min_value, - 'data-slider-max': max_value, - 'data-slider-step': step, - 'data-slider-value': initial, - } - ), + 'widget': Select(attrs=widget_attrs), } return [(self.data.name, ChoiceField, kwargs)] diff --git a/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py b/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py index 9bfcdd99..c72b874e 100644 --- a/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py +++ b/src/fobi/contrib/plugins/form_elements/fields/slider/forms.py @@ -3,6 +3,8 @@ from django.utils.translation import ugettext_lazy as _ from fobi.base import BaseFormFieldPluginForm, get_theme +from . import constants + from .settings import INITIAL, MAX_VALUE, MIN_VALUE, STEP __title__ = 'fobi.contrib.plugins.form_elements.fields.slider.forms' @@ -23,6 +25,13 @@ class SliderInputForm(forms.Form, BaseFormFieldPluginForm): ("min_value", MIN_VALUE), ("max_value", MAX_VALUE), ("step", STEP), + ("tooltip", constants.SLIDER_DEFAULT_TOOLTIP), + ("handle", constants.SLIDER_DEFAULT_HANDLE), + # ("disable_slider_background", False), + ("enable_ticks", False), + ("tick_label_start", ""), + ("tick_label_end", ""), + # ("custom_ticks", ""), ("help_text", ""), ("initial", INITIAL), ("required", False) @@ -70,6 +79,72 @@ class SliderInputForm(forms.Form, BaseFormFieldPluginForm): min_value=MIN_VALUE, max_value=MAX_VALUE ) + tooltip = forms.ChoiceField( + label=_("Tooltip"), + choices=constants.SLIDER_TOOLTIP_CHOICES, + required=False, + widget=forms.widgets.Select( + attrs={'class': theme.form_element_html_class} + ) + ) + handle = forms.ChoiceField( + label=_("Handle"), + choices=constants.SLIDER_HANDLE_CHOICES, + required=False, + widget=forms.widgets.Select( + attrs={'class': theme.form_element_html_class} + ) + ) + # disable_slider_background = forms.BooleanField( + # label=_("Disable slider background"), + # required=False, + # widget=forms.widgets.CheckboxInput( + # attrs={'class': theme.form_element_checkbox_html_class} + # ) + # ) + enable_ticks = forms.BooleanField( + label=_("Enable ticks"), + help_text=_("Adds ticks (endpoints) at start/end"), + required=False, + widget=forms.widgets.CheckboxInput( + attrs={'class': theme.form_element_checkbox_html_class} + ) + ) + tick_label_start = forms.CharField( + label=_("Tick start label"), + required=False, + widget=forms.widgets.TextInput( + attrs={'class': theme.form_element_html_class} + ) + ) + tick_label_end = forms.CharField( + label=_("Tick end label"), + required=False, + widget=forms.widgets.TextInput( + attrs={'class': theme.form_element_html_class} + ) + ) + # custom_ticks = forms.CharField( + # label=_("Custom ticks"), + # required=False, + # help_text=_("Enter single values/pairs per line. Example:
" + # "    1
" + # "    2
" + # "    3, Alpha
" + # "    4, Beta
" + # "

" + # "It finally transforms into the following HTML " + # "code:
" + # '    ' + # 'data-slider-ticks="[1, 2, 3, 4]"
' + # '    ' + # "data-slider-ticks-labels='" + # '["1", "2", "Alpha", "Beta"]' + # "'
"), + # widget=forms.widgets.Textarea( + # attrs={'class': theme.form_element_html_class} + # ) + # ) help_text = forms.CharField( label=_("Help text"), required=False, @@ -103,6 +178,8 @@ class SliderInputForm(forms.Form, BaseFormFieldPluginForm): min_value = self.cleaned_data['min_value'] initial = self.cleaned_data['initial'] step = self.cleaned_data['step'] + enable_ticks = self.cleaned_data['enable_ticks'] + handle = self.cleaned_data['handle'] if max_value < min_value: self.add_error( @@ -127,3 +204,11 @@ class SliderInputForm(forms.Form, BaseFormFieldPluginForm): 'min_value', _("`initial` should be >= than `min_value`.") ) + + if handle in (constants.SLIDER_HANDLE_TRIANGLE, + constants.SLIDER_HANDLE_CUSTOM) and enable_ticks: + self.add_error( + 'handle', + _("You are not allowed to use Triangle or Custom handles " + "with ticks enabled.") + ) diff --git a/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/css/fobi.plugin.slider-bootstrap3-widget.css b/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/css/fobi.plugin.slider-bootstrap3-widget.css index 2434c4d1..af379be3 100644 --- a/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/css/fobi.plugin.slider-bootstrap3-widget.css +++ b/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/css/fobi.plugin.slider-bootstrap3-widget.css @@ -1,3 +1,11 @@ .slider .slider-selection { - background: #BABABA; + background: none; + background-image: none; } +.slider .slider-selection.tick-slider-selection { + background: none; + background-image: none; +} +.slider .slider-tick.in-selection { + background-image: linear-gradient(to bottom, #f5f5f5 0, #c5c5c5 100%); +} \ No newline at end of file diff --git a/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/js/fobi.plugin.slider-bootstrap3-widget.js b/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/js/fobi.plugin.slider-bootstrap3-widget.js index 5b2c5da9..1812a764 100644 --- a/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/js/fobi.plugin.slider-bootstrap3-widget.js +++ b/src/fobi/contrib/themes/bootstrap3/widgets/form_elements/slider_bootstrap3_widget/static/bootstrap3/js/fobi.plugin.slider-bootstrap3-widget.js @@ -9,4 +9,5 @@ $(document).ready(function() { $('.slider').bootstrapSlider(); + $('.slider-no-background').bootstrapSlider(); });