From 889f8a2ec95be0d3aefe52f7c61e193404e175b8 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sun, 3 May 2020 19:56:13 +0300 Subject: [PATCH 01/36] add heading plugin --- .../contrib/bootstrap4_heading/__init__.py | 1 + .../contrib/bootstrap4_heading/cms_plugins.py | 42 ++++++++++++++++ .../contrib/bootstrap4_heading/constants.py | 47 ++++++++++++++++++ .../migrations/0001_initial.py | 37 ++++++++++++++ .../bootstrap4_heading/migrations/__init__.py | 1 + .../contrib/bootstrap4_heading/models.py | 48 +++++++++++++++++++ .../djangocms_bootstrap4/admin/spacing.html | 13 +++++ .../djangocms_bootstrap4/heading.html | 19 ++++++++ setup.py | 1 + 9 files changed, 209 insertions(+) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_heading/__init__.py create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_heading/cms_plugins.py create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_heading/constants.py create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/0001_initial.py create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/__init__.py create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_heading/models.py create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/admin/spacing.html create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/__init__.py b/djangocms_bootstrap4/contrib/bootstrap4_heading/__init__.py new file mode 100644 index 00000000..40a96afc --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_heading/cms_plugins.py new file mode 100644 index 00000000..227745d2 --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/cms_plugins.py @@ -0,0 +1,42 @@ +from cms.plugin_base import CMSPluginBase +from cms.plugin_pool import plugin_pool +from django.db import models +from django.forms import Textarea +from django.utils.translation import ugettext_lazy as _ + +from djangocms_bootstrap4.contrib.bootstrap4_heading.models import Bootstrap4Heading + + +@plugin_pool.register_plugin +class Bootstrap4HeadingPlugin(CMSPluginBase): + model = Bootstrap4Heading + name = _('Heading') + module = _('Bootstrap 4') + render_template = 'djangocms_bootstrap4/heading.html' + text_enabled = True + + fieldsets = [ + (None, { + 'fields': ( + 'text', + 'tag', + 'alignment', + 'color', + 'type', + ) + }), + (_('Advanced settings'), { + 'classes': ('collapse',), + 'fields': ( + 'size', + 'size_unit', + 'attributes', + ) + }), + ] + + formfield_overrides = { + models.TextField: { + 'widget': Textarea(attrs={'rows': 2}) + }, + } diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/constants.py b/djangocms_bootstrap4/contrib/bootstrap4_heading/constants.py new file mode 100644 index 00000000..ce4243af --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/constants.py @@ -0,0 +1,47 @@ +from django.conf import settings +from enumfields import Enum +from django.utils.translation import ugettext_lazy as _ + + +class SizeUnit(Enum): + PX = 'px' + REM = 'rem' + EM = 'em' + + class Labels: + PX = _('Pixels') + REM = _('Font size of the root element (rem)') + EM = _('Font size of the parent (em)') + + +class HeadingTag(Enum): + H1 = 'h1' + H2 = 'h2' + H3 = 'h3' + H4 = 'h4' + H5 = 'h5' + H6 = 'h6' + DIV = 'div' + P = 'p' + + +class HeadingColor(Enum): + DARK = 'dark' + WHITE = 'white' + + +class HeadingAlignment(Enum): + LEFT = 'left' + CENTER = 'center' + RIGHT = 'right' + + +class HeadingType(Enum): + NORMAL = 'normal' + + +HEADING_SIZE_UNIT_ENUM = getattr(settings, 'HEADING_SIZE_UNIT_ENUM', SizeUnit) +HEADING_TAG_ENUM = getattr(settings, 'HEADING_TAG_ENUM', HeadingTag) +HEADING_COLOR_ENUM = getattr(settings, 'HEADING_COLOR_ENUM', HeadingColor) +HEADING_ALIGNMENT_ENUM = getattr(settings, 'HEADING_ALIGNMENT_ENUM', HeadingAlignment) +HEADING_TYPE_ENUM = getattr(settings, 'HEADING_TYPE_ENUM', HeadingType) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/0001_initial.py b/djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/0001_initial.py new file mode 100644 index 00000000..94079f7a --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/0001_initial.py @@ -0,0 +1,37 @@ +# Generated by Django 2.2.12 on 2020-05-03 11:47 + +from django.db import migrations, models +import django.db.models.deletion +import djangocms_bootstrap4.contrib.bootstrap4_heading.constants +import djangocms_bootstrap4.fields +import enumfields.fields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('cms', '0022_auto_20180620_1551'), + ] + + operations = [ + migrations.CreateModel( + name='Bootstrap4Heading', + fields=[ + ('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='bootstrap4_heading_bootstrap4heading', serialize=False, to='cms.CMSPlugin')), + ('text', models.TextField(max_length=2048)), + ('tag', enumfields.fields.EnumField(default='h1', enum=djangocms_bootstrap4.contrib.bootstrap4_heading.constants.HeadingTag, max_length=32)), + ('alignment', enumfields.fields.EnumField(default='left', enum=djangocms_bootstrap4.contrib.bootstrap4_heading.constants.HeadingAlignment, max_length=32)), + ('size', models.FloatField(blank=True, help_text='Optional', null=True)), + ('size_unit', enumfields.fields.EnumField(default='px', enum=djangocms_bootstrap4.contrib.bootstrap4_heading.constants.SizeUnit, max_length=32)), + ('type', enumfields.fields.EnumField(blank=True, default='normal', enum=djangocms_bootstrap4.contrib.bootstrap4_heading.constants.HeadingType, max_length=32, null=True)), + ('color', enumfields.fields.EnumField(default='dark', enum=djangocms_bootstrap4.contrib.bootstrap4_heading.constants.HeadingColor, max_length=32)), + ('attributes', djangocms_bootstrap4.fields.AttributesField(blank=True, default=dict, verbose_name='Attributes')), + ], + options={ + 'abstract': False, + }, + bases=('cms.cmsplugin',), + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/__init__.py b/djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/__init__.py new file mode 100644 index 00000000..40a96afc --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/models.py b/djangocms_bootstrap4/contrib/bootstrap4_heading/models.py new file mode 100644 index 00000000..51085149 --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/models.py @@ -0,0 +1,48 @@ +from cms.models import CMSPlugin +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from enumfields import EnumField +from slugify import slugify + +from djangocms_bootstrap4.contrib.bootstrap4_heading.constants import HEADING_ALIGNMENT_ENUM +from djangocms_bootstrap4.contrib.bootstrap4_heading.constants import HEADING_COLOR_ENUM +from djangocms_bootstrap4.contrib.bootstrap4_heading.constants import HEADING_SIZE_UNIT_ENUM +from djangocms_bootstrap4.contrib.bootstrap4_heading.constants import HEADING_TAG_ENUM +from djangocms_bootstrap4.contrib.bootstrap4_heading.constants import HEADING_TYPE_ENUM +from djangocms_bootstrap4.fields import AttributesField + + +class Bootstrap4Heading(CMSPlugin): + text = models.TextField(max_length=2048) + + tag = EnumField( + HEADING_TAG_ENUM, default=HEADING_TAG_ENUM.H1, max_length=32, + ) + alignment = EnumField( + HEADING_ALIGNMENT_ENUM, default=HEADING_ALIGNMENT_ENUM.LEFT, max_length=32, + ) + + size = models.FloatField(blank=True, null=True, help_text=_("Optional")) + size_unit = EnumField( + HEADING_SIZE_UNIT_ENUM, default=HEADING_SIZE_UNIT_ENUM.PX, max_length=32, + ) + + type = EnumField( + HEADING_TYPE_ENUM, + default=HEADING_TYPE_ENUM.NORMAL, + max_length=32, + blank=True, null=True, + ) + color = EnumField( + HEADING_COLOR_ENUM, default=HEADING_COLOR_ENUM.DARK, max_length=32, + ) + + attributes = AttributesField() + + def get_anchor(self) -> str: + return slugify(self.text) + + def __str__(self) -> str: + if self.text: + return self.text + return "" diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/admin/spacing.html b/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/admin/spacing.html new file mode 100644 index 00000000..f401a7a3 --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/admin/spacing.html @@ -0,0 +1,13 @@ +{% extends "djangocms_bootstrap4/admin/base.html" %} +{% load i18n static %} + +{% block extrahead %} + {{ block.super }} + +{% endblock %} + +{% block field_sets %} +
+ {{ block.super }} +
+{% endblock %} diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html b/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html new file mode 100644 index 00000000..f51dc65f --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html @@ -0,0 +1,19 @@ +{% load cms_tags menu_tags %} + + +
+ <{{ instance.tag.value }} + class=" + heading-plugin + heading-plugin--{{ instance.type.value }} + heading-plugin--color-{{ instance.color.value }} + text-{{ instance.alignment.value }} + " + style=" + {% if instance.size %}font-size: {{ instance.size }}{{ instance.size_unit.value }}{% endif %} + " + id="{{ instance.get_anchor }}" + > + {{ instance.text|linebreaksbr }} + +
diff --git a/setup.py b/setup.py index 0cd03653..599d71d6 100644 --- a/setup.py +++ b/setup.py @@ -13,6 +13,7 @@ 'djangocms-icon>=1.4.0', 'djangocms-link>=2.5.0', 'djangocms-picture>=2.3.0', + 'django-enumfields>=2', ] From 122c8d8a229ec48608774103cfcd9b8adf4796ba Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sun, 3 May 2020 19:56:27 +0300 Subject: [PATCH 02/36] add new variables for container plugin --- .../contrib/bootstrap4_grid/constants.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py index 11220f58..2b8f8590 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py @@ -3,6 +3,7 @@ from django.conf import settings from django.utils.translation import ugettext_lazy as _ +from enumfields import Enum # The default grid size for Bootstrap 4 is 12. You can change this setting @@ -25,6 +26,30 @@ ), ) + +class GridContainerType(Enum): + pass + + +GRID_CONTAINER_TYPE_ENUM = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_GRID_CONTAINER_TYPE_ENUM', + GridContainerType, +) + + +class GridContainerMaxSize(Enum): + DEFAULT = '1140' + + + +GRID_CONTAINER_TYPE_ENUM = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_GRID_CONTAINER_TYPE_ENUM', + GridContainerType, +) + + # Options for flexbox on the alignment of the grid # https://flexbox.webflow.com/ GRID_ROW_VERTICAL_ALIGNMENT_CHOICES = ( From de8d3d7846626ca472b139c6a467ab73d99622ae Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sun, 24 May 2020 10:22:01 +0300 Subject: [PATCH 03/36] heading: conform to the settings.py vars convention --- .../contrib/bootstrap4_heading/constants.py | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/constants.py b/djangocms_bootstrap4/contrib/bootstrap4_heading/constants.py index ce4243af..cf48711e 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_heading/constants.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/constants.py @@ -40,8 +40,28 @@ class HeadingType(Enum): NORMAL = 'normal' -HEADING_SIZE_UNIT_ENUM = getattr(settings, 'HEADING_SIZE_UNIT_ENUM', SizeUnit) -HEADING_TAG_ENUM = getattr(settings, 'HEADING_TAG_ENUM', HeadingTag) -HEADING_COLOR_ENUM = getattr(settings, 'HEADING_COLOR_ENUM', HeadingColor) -HEADING_ALIGNMENT_ENUM = getattr(settings, 'HEADING_ALIGNMENT_ENUM', HeadingAlignment) -HEADING_TYPE_ENUM = getattr(settings, 'HEADING_TYPE_ENUM', HeadingType) +HEADING_SIZE_UNIT_ENUM = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_HEADING_SIZE_UNIT_ENUM', + SizeUnit, +) +HEADING_TAG_ENUM = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_HEADING_TAG_ENUM', + HeadingTag, +) +HEADING_COLOR_ENUM = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_HEADING_COLOR_ENUM', + HeadingColor, +) +HEADING_ALIGNMENT_ENUM = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_HEADING_ALIGNMENT_ENUM', + HeadingAlignment, +) +HEADING_TYPE_ENUM = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_HEADING_TYPE_ENUM', + HeadingType, +) From 9cd07f46a7826e8ce70218cac23c3ce905e6353a Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sun, 24 May 2020 11:01:24 +0300 Subject: [PATCH 04/36] container: add name field and use enum types --- .../contrib/bootstrap4_grid/cms_plugins.py | 1 + .../contrib/bootstrap4_grid/constants.py | 41 ++++++--------- ...05_add_name_field_and_use_enum_for_type.py | 25 +++++++++ .../contrib/bootstrap4_grid/models.py | 51 +++++++++---------- 4 files changed, 66 insertions(+), 52 deletions(-) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0005_add_name_field_and_use_enum_for_type.py diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index 40ba4504..413d8f70 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -29,6 +29,7 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): fieldsets = [ (None, { 'fields': ( + 'name', 'container_type', ) }), diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py index 2b8f8590..b918f86d 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py @@ -15,37 +15,15 @@ 12, ) -# Bootstrap 4 provides 2 container types, .container and .container-fluid -# https://getbootstrap.com/docs/4.0/layout/grid/#no-gutters -GRID_CONTAINER_CHOICES = getattr( - settings, - 'DJANGOCMS_BOOTSTRAP4_GRID_CONTAINERS', - ( - ('container', _('Container')), - ('container-fluid', _('Fluid container')), - ), -) - class GridContainerType(Enum): - pass + DYNAMIC_WIDTH = 'container' + FULL_WIDTH = 'container-fluid' -GRID_CONTAINER_TYPE_ENUM = getattr( +GRID_CONTAINER_TYPE: GridContainerType = getattr( settings, - 'DJANGOCMS_BOOTSTRAP4_GRID_CONTAINER_TYPE_ENUM', - GridContainerType, -) - - -class GridContainerMaxSize(Enum): - DEFAULT = '1140' - - - -GRID_CONTAINER_TYPE_ENUM = getattr( - settings, - 'DJANGOCMS_BOOTSTRAP4_GRID_CONTAINER_TYPE_ENUM', + 'DJANGOCMS_BOOTSTRAP4_GRID_CONTAINER_TYPE', GridContainerType, ) @@ -81,3 +59,14 @@ class GridContainerMaxSize(Enum): ('', _('Empty')) ), ) + + +# deprecated, left only for migrations +GRID_CONTAINER_CHOICES = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_GRID_CONTAINERS', + ( + ('container', _('Container')), + ('container-fluid', _('Fluid container')), + ), +) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0005_add_name_field_and_use_enum_for_type.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0005_add_name_field_and_use_enum_for_type.py new file mode 100644 index 00000000..1b9c26ae --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0005_add_name_field_and_use_enum_for_type.py @@ -0,0 +1,25 @@ +# Generated by Django 2.2.12 on 2020-05-24 02:55 + +from django.db import migrations, models +import djangocms_bootstrap4.contrib.bootstrap4_grid.constants +import enumfields.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('bootstrap4_grid', '0004_remove_bootstrap4gridcolumn_column_size'), + ] + + operations = [ + migrations.AddField( + model_name='bootstrap4gridcontainer', + name='name', + field=models.CharField(blank=True, help_text='Shown only to the admins in the structure mode for better orientation', max_length=1024, null=True), + ), + migrations.AlterField( + model_name='bootstrap4gridcontainer', + name='container_type', + field=enumfields.fields.EnumField(default='container', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.constants.GridContainerType, max_length=255, verbose_name='Container type'), + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index 57fd6366..a5aa1b34 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -3,25 +3,24 @@ from functools import partial +from cms.models import CMSPlugin from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext - -from cms.models import CMSPlugin - +from enumfields import EnumField from six import python_2_unicode_compatible from djangocms_bootstrap4.constants import DEVICE_SIZES -from djangocms_bootstrap4.fields import ( - AttributesField, IntegerRangeField, TagTypeField, -) +from djangocms_bootstrap4.fields import AttributesField +from djangocms_bootstrap4.fields import IntegerRangeField +from djangocms_bootstrap4.fields import TagTypeField from djangocms_bootstrap4.helpers import mark_safe_lazy - -from .constants import ( - GRID_COLUMN_ALIGNMENT_CHOICES, GRID_COLUMN_CHOICES, GRID_CONTAINER_CHOICES, - GRID_ROW_HORIZONTAL_ALIGNMENT_CHOICES, GRID_ROW_VERTICAL_ALIGNMENT_CHOICES, - GRID_SIZE, -) +from .constants import GRID_COLUMN_ALIGNMENT_CHOICES +from .constants import GRID_COLUMN_CHOICES +from .constants import GRID_CONTAINER_TYPE +from .constants import GRID_ROW_HORIZONTAL_ALIGNMENT_CHOICES +from .constants import GRID_ROW_VERTICAL_ALIGNMENT_CHOICES +from .constants import GRID_SIZE @python_2_unicode_compatible @@ -30,28 +29,28 @@ class Bootstrap4GridContainer(CMSPlugin): Layout > Grid: "Container" Plugin https://getbootstrap.com/docs/4.0/layout/grid/ """ - container_type = models.CharField( + name = models.CharField( + max_length=1024, + null=True, blank=True, + help_text=_('Shown only to the admins in the structure mode for better orientation'), + ) + container_type = EnumField( + GRID_CONTAINER_TYPE, + default=GRID_CONTAINER_TYPE.DYNAMIC_WIDTH, verbose_name=_('Container type'), - choices=GRID_CONTAINER_CHOICES, - default=GRID_CONTAINER_CHOICES[0][0], max_length=255, - help_text=mark_safe_lazy(_( - 'Defines if the grid should use fixed width (.container) ' - 'or fluid width (.container-fluid).' - )), ) tag_type = TagTypeField() attributes = AttributesField() - def __str__(self): + def __str__(self) -> str: return str(self.pk) - def get_short_description(self): - text = '' - for item in GRID_CONTAINER_CHOICES: - if item[0] == self.container_type: - text = item[1] - return '({})'.format(text) + def get_short_description(self) -> str: + if self.name: + return self.name + else: + return f'({self.type.label})' @python_2_unicode_compatible From bf8c4fb79ae594c6bcfc0401b55a6a8bba7362ee Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sun, 24 May 2020 12:11:34 +0300 Subject: [PATCH 05/36] picture: add css d-flex by default --- djangocms_bootstrap4/contrib/bootstrap4_picture/cms_plugins.py | 1 + 1 file changed, 1 insertion(+) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_picture/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_picture/cms_plugins.py index 7ded0252..5418754d 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_picture/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_picture/cms_plugins.py @@ -46,6 +46,7 @@ def render(self, context, instance, placeholder): classes = concat_classes(link_classes + [ instance.attributes.get('class'), + 'd-flex', ]) instance.attributes['class'] = classes From e6f2beba2fb31c2648ec81b612ef59b3e51c4db0 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sun, 24 May 2020 12:22:10 +0300 Subject: [PATCH 06/36] picture: fix alignment config with caption --- .../contrib/bootstrap4_picture/cms_plugins.py | 2 +- .../djangocms_picture/default/picture.html | 81 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_picture/templates/djangocms_picture/default/picture.html diff --git a/djangocms_bootstrap4/contrib/bootstrap4_picture/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_picture/cms_plugins.py index 5418754d..e65e0e39 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_picture/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_picture/cms_plugins.py @@ -46,7 +46,7 @@ def render(self, context, instance, placeholder): classes = concat_classes(link_classes + [ instance.attributes.get('class'), - 'd-flex', + 'flex-column', ]) instance.attributes['class'] = classes diff --git a/djangocms_bootstrap4/contrib/bootstrap4_picture/templates/djangocms_picture/default/picture.html b/djangocms_bootstrap4/contrib/bootstrap4_picture/templates/djangocms_picture/default/picture.html new file mode 100644 index 00000000..ef611bd3 --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_picture/templates/djangocms_picture/default/picture.html @@ -0,0 +1,81 @@ +{% load thumbnail %} + +{% if picture_link %} + +{% endif %} + +{# start render figure/figcaption #} +{% if instance.caption_text %} +
+{% endif %} +{# end render figure/figcaption #} + + +{% if instance.attributes.alt %}{{ instance.attributes.alt }}{% elif instance.picture.default_alt_text %}{{ instance.picture.default_alt_text }}{% endif %} + +{# start render figure/figcaption #} +{% if instance.caption_text %} +
{{ instance.caption_text }}
+
+{% endif %} +{# end render figure/figcaption #} + +{% if picture_link %} +
+{% endif %} + +{% comment %} + # https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img + # https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure + # https://github.com/divio/django-filer/blob/master/filer/models/imagemodels.py + # http://easy-thumbnails.readthedocs.io/en/2.1/usage/#templates + {{ instance.picture }} + # Available variables: + {{ instance.img_src }} + {{ instance.width }} + {{ instance.height }} + {{ instance.alignment }} + {{ instance.caption_text }} + {{ instance.img_srcset_data }} or {{ img_srcset_data }} + {{ instance.attributes_str }} + # picture helper + {{ instance.get_size }} or {{ picture_size }} + # link settings + {{ instance.link_url }} + {{ instance.link_page }} + {{ instance.link_target }} + {{ instance.link_attributes_str }} + # link helper + {{ instance.get_link }} or {{ picture_link }} + # cropping settings + {{ instance.use_automatic_scaling }} + {{ instance.use_no_cropping }} + {{ instance.use_crop }} + {{ instance.use_upscale }} + {{ instance.thumbnail_options }} + # activate DJANGOCMS_PICTURE_NESTING to enable nested plugins: + {% for plugin in instance.child_plugin_instances %} + {% render_plugin plugin %} + {% endfor %} +{% endcomment %} From fb4ef1ceaa0b2b3ded0adcdaad5be14a9de7dc5a Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Fri, 29 May 2020 16:56:06 +0300 Subject: [PATCH 07/36] heading: rename field `text` to `name` for djangocms-text-ckeditor#528 --- .../0002_rename_field_text_to_name.py | 21 +++++++++++++++++++ .../contrib/bootstrap4_heading/models.py | 9 ++++---- 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/0002_rename_field_text_to_name.py diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/0002_rename_field_text_to_name.py b/djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/0002_rename_field_text_to_name.py new file mode 100644 index 00000000..965595ae --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/migrations/0002_rename_field_text_to_name.py @@ -0,0 +1,21 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bootstrap4_heading', '0001_initial'), + ] + + operations = [ + migrations.RenameField( + model_name='bootstrap4heading', + old_name='text', + new_name='name', + ), + migrations.AlterField( + model_name='bootstrap4heading', + name='name', + field=models.TextField(max_length=2048, verbose_name='Text'), + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/models.py b/djangocms_bootstrap4/contrib/bootstrap4_heading/models.py index 51085149..91f40aae 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_heading/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/models.py @@ -13,7 +13,8 @@ class Bootstrap4Heading(CMSPlugin): - text = models.TextField(max_length=2048) + # this name isn't self-explanatory because djangocms-text-ckeditor#528 + name = models.TextField(max_length=2048, verbose_name=_("Text")) tag = EnumField( HEADING_TAG_ENUM, default=HEADING_TAG_ENUM.H1, max_length=32, @@ -40,9 +41,9 @@ class Bootstrap4Heading(CMSPlugin): attributes = AttributesField() def get_anchor(self) -> str: - return slugify(self.text) + return slugify(self.name) def __str__(self) -> str: - if self.text: - return self.text + if self.name: + return self.name return "" From 2df934f7040e69b374dbd39bd158d834e910efb2 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sat, 30 May 2020 13:42:26 +0300 Subject: [PATCH 08/36] heading: fix renamed field `name` (djangocms-text-ckeditor#528) --- djangocms_bootstrap4/contrib/bootstrap4_heading/cms_plugins.py | 2 +- .../templates/djangocms_bootstrap4/heading.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_heading/cms_plugins.py index 227745d2..9c6460a8 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_heading/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/cms_plugins.py @@ -18,7 +18,7 @@ class Bootstrap4HeadingPlugin(CMSPluginBase): fieldsets = [ (None, { 'fields': ( - 'text', + 'name', 'tag', 'alignment', 'color', diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html b/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html index f51dc65f..d76b087c 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html @@ -14,6 +14,6 @@ " id="{{ instance.get_anchor }}" > - {{ instance.text|linebreaksbr }} + {{ instance.name|linebreaksbr }} From ce1417e57ce152c349c265886374c51163465828 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sat, 30 May 2020 16:25:04 +0300 Subject: [PATCH 09/36] container: allow to configure background and spacing --- .../contrib/bootstrap4_grid/cms_plugins.py | 9 ++++-- .../contrib/bootstrap4_grid/constants.py | 31 +++++++++++++++++++ .../0006_add_fields_background_and_spacing.py | 25 +++++++++++++++ .../contrib/bootstrap4_grid/models.py | 17 ++++++++-- 4 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0006_add_fields_background_and_spacing.py diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index 413d8f70..f182626a 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -27,10 +27,13 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): allow_children = True fieldsets = [ + (None, { 'fields': ( 'name', 'container_type', + 'background', + 'spacing', ) }), (_('Advanced settings'), { @@ -45,13 +48,13 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): def render(self, context, instance, placeholder): classes = concat_classes([ instance.container_type, + instance.background, + instance.spacing, instance.attributes.get('class'), ]) instance.attributes['class'] = classes - return super(Bootstrap4GridContainerPlugin, self).render( - context, instance, placeholder - ) + return super().render(context, instance, placeholder) class Bootstrap4GridRowPlugin(CMSPluginBase): diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py index b918f86d..0280b37d 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py @@ -17,6 +17,9 @@ class GridContainerType(Enum): + """ + contains css classes + """ DYNAMIC_WIDTH = 'container' FULL_WIDTH = 'container-fluid' @@ -28,6 +31,34 @@ class GridContainerType(Enum): ) +class GridContainerBackground(Enum): + """ + contains css classes + """ + NONE = 'background-none' + + +GRID_CONTAINER_BACKGROUND: GridContainerBackground = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_GRID_CONTAINER_BACKGROUND', + GridContainerBackground, +) + + +class GridContainerSpacing(Enum): + """ + contains css classes + """ + NONE = 'spacing-none' + + +GRID_CONTAINER_SPACING: GridContainerSpacing = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_GRID_CONTAINER_SPACING', + GridContainerSpacing, +) + + # Options for flexbox on the alignment of the grid # https://flexbox.webflow.com/ GRID_ROW_VERTICAL_ALIGNMENT_CHOICES = ( diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0006_add_fields_background_and_spacing.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0006_add_fields_background_and_spacing.py new file mode 100644 index 00000000..684c7811 --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0006_add_fields_background_and_spacing.py @@ -0,0 +1,25 @@ +# Generated by Django 2.2.12 on 2020-05-30 13:23 + +from django.db import migrations +import djangocms_bootstrap4.contrib.bootstrap4_grid.constants +import enumfields.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('bootstrap4_grid', '0005_add_name_field_and_use_enum_for_type'), + ] + + operations = [ + migrations.AddField( + model_name='bootstrap4gridcontainer', + name='background', + field=enumfields.fields.EnumField(default='background-none', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.constants.GridContainerBackground, max_length=255, verbose_name='Background'), + ), + migrations.AddField( + model_name='bootstrap4gridcontainer', + name='spacing', + field=enumfields.fields.EnumField(default='spacing-none', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.constants.GridContainerSpacing, max_length=255, verbose_name='Spacing'), + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index a5aa1b34..b47dbb6f 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from functools import partial from cms.models import CMSPlugin @@ -17,6 +14,8 @@ from djangocms_bootstrap4.helpers import mark_safe_lazy from .constants import GRID_COLUMN_ALIGNMENT_CHOICES from .constants import GRID_COLUMN_CHOICES +from .constants import GRID_CONTAINER_BACKGROUND +from .constants import GRID_CONTAINER_SPACING from .constants import GRID_CONTAINER_TYPE from .constants import GRID_ROW_HORIZONTAL_ALIGNMENT_CHOICES from .constants import GRID_ROW_VERTICAL_ALIGNMENT_CHOICES @@ -40,6 +39,18 @@ class Bootstrap4GridContainer(CMSPlugin): verbose_name=_('Container type'), max_length=255, ) + background = EnumField( + GRID_CONTAINER_BACKGROUND, + default=GRID_CONTAINER_BACKGROUND.NONE, + verbose_name=_('Background'), + max_length=255, + ) + spacing = EnumField( + GRID_CONTAINER_SPACING, + default=GRID_CONTAINER_SPACING.NONE, + verbose_name=_('Spacing'), + max_length=255, + ) tag_type = TagTypeField() attributes = AttributesField() From 06b177cc9070c1d115301f540746fc48114d95a4 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sat, 30 May 2020 19:09:28 +0300 Subject: [PATCH 10/36] container: fix enums values render --- djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index f182626a..1d50f7bd 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -47,9 +47,9 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): def render(self, context, instance, placeholder): classes = concat_classes([ - instance.container_type, - instance.background, - instance.spacing, + instance.container_type.value, + instance.background.value, + instance.spacing.value, instance.attributes.get('class'), ]) instance.attributes['class'] = classes From 3ec58d16ec236064aa3a142d81027317af18433d Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sat, 30 May 2020 22:36:23 +0300 Subject: [PATCH 11/36] container: fix incorrect attribute call --- djangocms_bootstrap4/contrib/bootstrap4_grid/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index b47dbb6f..e433d846 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -61,7 +61,7 @@ def get_short_description(self) -> str: if self.name: return self.name else: - return f'({self.type.label})' + return f'({self.container_type.label})' @python_2_unicode_compatible From 2da1d8979b5e4cb505b1a5223736b881746adee9 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Tue, 9 Jun 2020 14:52:52 +0300 Subject: [PATCH 12/36] grid: add ckeditor css classes for container --- .../contrib/bootstrap4_grid/cms_plugins.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index 1d50f7bd..2697b6fd 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +from cms.models import CMSPlugin +from cms.utils.plugins import get_plugin_model from django.utils.translation import ugettext_lazy as _ from cms.plugin_base import CMSPluginBase @@ -56,6 +58,16 @@ def render(self, context, instance, placeholder): return super().render(context, instance, placeholder) + @classmethod + def get_child_ckeditor_body_css_class(cls, plugin: CMSPlugin) -> str: + plugin_model = get_plugin_model(plugin.plugin_type) + instance: Bootstrap4GridContainer = plugin_model.objects.get(pk=plugin.pk) + + css_classes = 'container-plugin' + css_classes += f' container-plugin--{instance.background.value}' + + return css_classes + class Bootstrap4GridRowPlugin(CMSPluginBase): """ From 5ea5100b9d7b293589874f5c3a39845cb297ce12 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Wed, 10 Jun 2020 20:39:42 +0300 Subject: [PATCH 13/36] grid/container: add vertical spacer type --- .../contrib/bootstrap4_grid/cms_plugins.py | 17 ++++----- .../0007_add_field_spacing_vertical_type.py | 36 +++++++++++++++++++ ...0008_rename_spacing_to_spacing_vertical.py | 18 ++++++++++ .../contrib/bootstrap4_grid/models.py | 22 ++++++++++-- 4 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0008_rename_spacing_to_spacing_vertical.py diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index 2697b6fd..4108c0b8 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -27,15 +27,15 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): module = _('Bootstrap 4') render_template = 'djangocms_bootstrap4/grid_container.html' allow_children = True + plugin_css_class = 'container-plugin' fieldsets = [ - (None, { 'fields': ( 'name', 'container_type', 'background', - 'spacing', + ('spacing_vertical', 'spacing_vertical_type'), ) }), (_('Advanced settings'), { @@ -47,11 +47,12 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): }), ] - def render(self, context, instance, placeholder): + def render(self, context, instance: Bootstrap4GridContainer, placeholder): classes = concat_classes([ + self.plugin_css_class, instance.container_type.value, - instance.background.value, - instance.spacing.value, + f'{self.plugin_css_class}--{instance.background.value}', + f'{self.plugin_css_class}--{instance.spacing_vertical.value}-{instance.spacing_vertical_type.value}', instance.attributes.get('class'), ]) instance.attributes['class'] = classes @@ -62,11 +63,7 @@ def render(self, context, instance, placeholder): def get_child_ckeditor_body_css_class(cls, plugin: CMSPlugin) -> str: plugin_model = get_plugin_model(plugin.plugin_type) instance: Bootstrap4GridContainer = plugin_model.objects.get(pk=plugin.pk) - - css_classes = 'container-plugin' - css_classes += f' container-plugin--{instance.background.value}' - - return css_classes + return f'{cls.plugin_css_class} {cls.plugin_css_class}--{instance.background.value}' class Bootstrap4GridRowPlugin(CMSPluginBase): diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py new file mode 100644 index 00000000..5d92c656 --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py @@ -0,0 +1,36 @@ +# Generated by Django 2.2.13 on 2020-06-10 11:28 + +from django.db import migrations +import djangocms_bootstrap4.contrib.bootstrap4_grid.models +import enumfields.fields +import settings + + +class Migration(migrations.Migration): + + dependencies = [ + ('bootstrap4_grid', '0006_add_fields_background_and_spacing'), + ] + + operations = [ + migrations.AddField( + model_name='bootstrap4gridcontainer', + name='spacing_vertical_type', + field=enumfields.fields.EnumField(default='margin', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.models.SpacingVerticalType, max_length=255, verbose_name='Vertical spacing type'), + ), + migrations.AlterField( + model_name='bootstrap4gridcontainer', + name='background', + field=enumfields.fields.EnumField(default='background-none', enum=settings.GridContainerBackground, max_length=255, verbose_name='Background'), + ), + migrations.AlterField( + model_name='bootstrap4gridcontainer', + name='container_type', + field=enumfields.fields.EnumField(default='container', enum=settings.GridContainerType, max_length=255, verbose_name='Container width'), + ), + migrations.AlterField( + model_name='bootstrap4gridcontainer', + name='spacing', + field=enumfields.fields.EnumField(default='spacing-none', enum=settings.GridContainerSpacing, max_length=255, verbose_name='Vertical spacing'), + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0008_rename_spacing_to_spacing_vertical.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0008_rename_spacing_to_spacing_vertical.py new file mode 100644 index 00000000..5d88a808 --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0008_rename_spacing_to_spacing_vertical.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.13 on 2020-06-10 11:29 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('bootstrap4_grid', '0007_add_field_spacing_vertical_type'), + ] + + operations = [ + migrations.RenameField( + model_name='bootstrap4gridcontainer', + old_name='spacing', + new_name='spacing_vertical', + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index e433d846..59691435 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -4,6 +4,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext +from enumfields import Enum from enumfields import EnumField from six import python_2_unicode_compatible @@ -22,6 +23,15 @@ from .constants import GRID_SIZE +class SpacingVerticalType(Enum): + MARGIN = 'margin' + PADDING = 'padding' + + class Labels: + MARGIN = _('External spacing') + PADDING = _('Internal spacing') + + @python_2_unicode_compatible class Bootstrap4GridContainer(CMSPlugin): """ @@ -36,7 +46,7 @@ class Bootstrap4GridContainer(CMSPlugin): container_type = EnumField( GRID_CONTAINER_TYPE, default=GRID_CONTAINER_TYPE.DYNAMIC_WIDTH, - verbose_name=_('Container type'), + verbose_name=_('Container width'), max_length=255, ) background = EnumField( @@ -45,10 +55,16 @@ class Bootstrap4GridContainer(CMSPlugin): verbose_name=_('Background'), max_length=255, ) - spacing = EnumField( + spacing_vertical = EnumField( GRID_CONTAINER_SPACING, default=GRID_CONTAINER_SPACING.NONE, - verbose_name=_('Spacing'), + verbose_name=_('Vertical spacing'), + max_length=255, + ) + spacing_vertical_type = EnumField( + SpacingVerticalType, + default=SpacingVerticalType.MARGIN, + verbose_name=_('Vertical spacing type'), max_length=255, ) tag_type = TagTypeField() From fb1dbf3268fc940b8f169847a8c9e5d863d210a1 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Wed, 10 Jun 2020 22:04:36 +0300 Subject: [PATCH 14/36] grid: fix migrations --- .../migrations/0007_add_field_spacing_vertical_type.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py index 5d92c656..18e90c38 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py @@ -2,8 +2,8 @@ from django.db import migrations import djangocms_bootstrap4.contrib.bootstrap4_grid.models +import djangocms_bootstrap4.contrib.bootstrap4_grid.constants import enumfields.fields -import settings class Migration(migrations.Migration): @@ -21,16 +21,16 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='bootstrap4gridcontainer', name='background', - field=enumfields.fields.EnumField(default='background-none', enum=settings.GridContainerBackground, max_length=255, verbose_name='Background'), + field=enumfields.fields.EnumField(default='background-none', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.constants.GridContainerBackground, max_length=255, verbose_name='Background'), ), migrations.AlterField( model_name='bootstrap4gridcontainer', name='container_type', - field=enumfields.fields.EnumField(default='container', enum=settings.GridContainerType, max_length=255, verbose_name='Container width'), + field=enumfields.fields.EnumField(default='container', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.constants.GridContainerType, max_length=255, verbose_name='Container width'), ), migrations.AlterField( model_name='bootstrap4gridcontainer', name='spacing', - field=enumfields.fields.EnumField(default='spacing-none', enum=settings.GridContainerSpacing, max_length=255, verbose_name='Vertical spacing'), + field=enumfields.fields.EnumField(default='spacing-none', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.constants.GridContainerSpacing, max_length=255, verbose_name='Vertical spacing'), ), ] From 34968cb4cf5d9812d3b4a4f2f911e0a01d0055ae Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Wed, 10 Jun 2020 23:03:25 +0300 Subject: [PATCH 15/36] grid: add gutters configuration --- .../contrib/bootstrap4_grid/cms_plugins.py | 16 ++++++---- .../migrations/0009_add_fields_gutters.py | 23 +++++++++++++++ .../contrib/bootstrap4_grid/models.py | 29 ++++++++++++++++++- 3 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0009_add_fields_gutters.py diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index 4108c0b8..6cb34395 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -27,7 +27,7 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): module = _('Bootstrap 4') render_template = 'djangocms_bootstrap4/grid_container.html' allow_children = True - plugin_css_class = 'container-plugin' + css_class = 'container-plugin' fieldsets = [ (None, { @@ -49,10 +49,10 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): def render(self, context, instance: Bootstrap4GridContainer, placeholder): classes = concat_classes([ - self.plugin_css_class, + self.css_class, instance.container_type.value, - f'{self.plugin_css_class}--{instance.background.value}', - f'{self.plugin_css_class}--{instance.spacing_vertical.value}-{instance.spacing_vertical_type.value}', + f'{self.css_class}--{instance.background.value}', + f'{self.css_class}--{instance.spacing_vertical.value}-{instance.spacing_vertical_type.value}', instance.attributes.get('class'), ]) instance.attributes['class'] = classes @@ -63,7 +63,7 @@ def render(self, context, instance: Bootstrap4GridContainer, placeholder): def get_child_ckeditor_body_css_class(cls, plugin: CMSPlugin) -> str: plugin_model = get_plugin_model(plugin.plugin_type) instance: Bootstrap4GridContainer = plugin_model.objects.get(pk=plugin.pk) - return f'{cls.plugin_css_class} {cls.plugin_css_class}--{instance.background.value}' + return f'{cls.css_class} {cls.css_class}--{instance.background.value}' class Bootstrap4GridRowPlugin(CMSPluginBase): @@ -79,12 +79,14 @@ class Bootstrap4GridRowPlugin(CMSPluginBase): render_template = 'djangocms_bootstrap4/grid_row.html' allow_children = True child_classes = ['Bootstrap4GridColumnPlugin'] + css_class = 'row-plugin' fieldsets = [ (None, { 'fields': ( 'create', ('vertical_alignment', 'horizontal_alignment'), + ('gutters_horizontal', 'gutters_vertical'), ) }), (_('Advanced settings'), { @@ -115,10 +117,12 @@ def save_model(self, request, obj, form, change): ) obj.add_child(instance=col) - def render(self, context, instance, placeholder): + def render(self, context, instance: Bootstrap4GridRow, placeholder): gutter = 'no-gutters' if instance.gutters else '' classes = concat_classes([ 'row', + f'{self.css_class}--gutters-horizontal-{instance.gutters_horizontal.value}', + f'{self.css_class}--gutters-vertical-{instance.gutters_vertical.value}', instance.vertical_alignment, instance.horizontal_alignment, gutter, diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0009_add_fields_gutters.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0009_add_fields_gutters.py new file mode 100644 index 00000000..a3c34c47 --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0009_add_fields_gutters.py @@ -0,0 +1,23 @@ +from django.db import migrations +import djangocms_bootstrap4.contrib.bootstrap4_grid.models +import enumfields.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('bootstrap4_grid', '0008_rename_spacing_to_spacing_vertical'), + ] + + operations = [ + migrations.AddField( + model_name='bootstrap4gridrow', + name='gutters_horizontal', + field=enumfields.fields.EnumField(default='normal', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.models.GuttersHorizontal, max_length=32), + ), + migrations.AddField( + model_name='bootstrap4gridrow', + name='gutters_vertical', + field=enumfields.fields.EnumField(default='none', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.models.GuttersVertical, max_length=32), + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index 59691435..d7bd6298 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -80,7 +80,22 @@ def get_short_description(self) -> str: return f'({self.container_type.label})' -@python_2_unicode_compatible +class GuttersVertical(Enum): + NONE = 'none' + SMALL = 'small' + NORMAL = 'normal' + LARGE = 'large' + EXTRA_LARGE = 'extra_large' + + +class GuttersHorizontal(Enum): + NONE = 'none' + SMALL = 'small' + NORMAL = 'normal' + LARGE = 'large' + EXTRA_LARGE = 'extra_large' + + class Bootstrap4GridRow(CMSPlugin): """ Layout > Grid: "Row" Plugin @@ -106,6 +121,18 @@ class Bootstrap4GridRow(CMSPlugin): .format(link='https://getbootstrap.com/docs/4.0/layout/grid/#horizontal-alignment') ), ) + gutters_vertical = EnumField( + GuttersVertical, + default=GuttersVertical.NONE, + max_length=32, + verbose_name=_("Vertical spacing between the columns inside"), + ) + gutters_horizontal = EnumField( + GuttersHorizontal, + default=GuttersHorizontal.NORMAL, + max_length=32, + verbose_name=_("Horizontal spacing between the columns inside"), + ) gutters = models.BooleanField( verbose_name=_('Remove gutters'), default=False, From 47c80c5e131dc3b32989ead0464c7c45e0a345f4 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Wed, 10 Jun 2020 23:04:40 +0300 Subject: [PATCH 16/36] grid: replace verbose_name with help_text --- djangocms_bootstrap4/contrib/bootstrap4_grid/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index d7bd6298..a01ae884 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -125,13 +125,13 @@ class Bootstrap4GridRow(CMSPlugin): GuttersVertical, default=GuttersVertical.NONE, max_length=32, - verbose_name=_("Vertical spacing between the columns inside"), + help_text=_("Vertical spacing between the columns inside"), ) gutters_horizontal = EnumField( GuttersHorizontal, default=GuttersHorizontal.NORMAL, max_length=32, - verbose_name=_("Horizontal spacing between the columns inside"), + help_text=_("Horizontal spacing between the columns inside"), ) gutters = models.BooleanField( verbose_name=_('Remove gutters'), From 082574b0a72f42aa50e452b44f97ecb13ef9ebcb Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Wed, 10 Jun 2020 23:39:40 +0300 Subject: [PATCH 17/36] grid: drop spacing vertical type field there's a better way to handle it on the user side --- .../contrib/bootstrap4_grid/cms_plugins.py | 4 ++-- .../0007_add_field_spacing_vertical_type.py | 13 ++++++++++--- .../0010_drop_field_spacing_vertical_type.py | 15 +++++++++++++++ .../contrib/bootstrap4_grid/models.py | 15 --------------- 4 files changed, 27 insertions(+), 20 deletions(-) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0010_drop_field_spacing_vertical_type.py diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index 6cb34395..92efa9d3 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -35,7 +35,7 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): 'name', 'container_type', 'background', - ('spacing_vertical', 'spacing_vertical_type'), + 'spacing_vertical', ) }), (_('Advanced settings'), { @@ -52,7 +52,7 @@ def render(self, context, instance: Bootstrap4GridContainer, placeholder): self.css_class, instance.container_type.value, f'{self.css_class}--{instance.background.value}', - f'{self.css_class}--{instance.spacing_vertical.value}-{instance.spacing_vertical_type.value}', + f'{self.css_class}--{instance.spacing_vertical.value}', instance.attributes.get('class'), ]) instance.attributes['class'] = classes diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py index 18e90c38..bfef5429 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0007_add_field_spacing_vertical_type.py @@ -1,9 +1,16 @@ -# Generated by Django 2.2.13 on 2020-06-10 11:28 - from django.db import migrations import djangocms_bootstrap4.contrib.bootstrap4_grid.models import djangocms_bootstrap4.contrib.bootstrap4_grid.constants import enumfields.fields +from enumfields import Enum + + +class SpacingVerticalType(Enum): + """ + for backward migration compatibility + """ + MARGIN = 'margin' + PADDING = 'padding' class Migration(migrations.Migration): @@ -16,7 +23,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='bootstrap4gridcontainer', name='spacing_vertical_type', - field=enumfields.fields.EnumField(default='margin', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.models.SpacingVerticalType, max_length=255, verbose_name='Vertical spacing type'), + field=enumfields.fields.EnumField(default='margin', enum=SpacingVerticalType, max_length=255, verbose_name='Vertical spacing type'), ), migrations.AlterField( model_name='bootstrap4gridcontainer', diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0010_drop_field_spacing_vertical_type.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0010_drop_field_spacing_vertical_type.py new file mode 100644 index 00000000..e75bb55b --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0010_drop_field_spacing_vertical_type.py @@ -0,0 +1,15 @@ +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('bootstrap4_grid', '0009_add_fields_gutters'), + ] + + operations = [ + migrations.RemoveField( + model_name='bootstrap4gridcontainer', + name='spacing_vertical_type', + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index a01ae884..379d46c6 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -23,15 +23,6 @@ from .constants import GRID_SIZE -class SpacingVerticalType(Enum): - MARGIN = 'margin' - PADDING = 'padding' - - class Labels: - MARGIN = _('External spacing') - PADDING = _('Internal spacing') - - @python_2_unicode_compatible class Bootstrap4GridContainer(CMSPlugin): """ @@ -61,12 +52,6 @@ class Bootstrap4GridContainer(CMSPlugin): verbose_name=_('Vertical spacing'), max_length=255, ) - spacing_vertical_type = EnumField( - SpacingVerticalType, - default=SpacingVerticalType.MARGIN, - verbose_name=_('Vertical spacing type'), - max_length=255, - ) tag_type = TagTypeField() attributes = AttributesField() From a9d7972157cae66a887bfcbe10db2c74908b2636 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Fri, 12 Jun 2020 16:51:55 +0300 Subject: [PATCH 18/36] row: drop the horizontal spacing field it isn't feasible since bootstrap 4 is hardcoded for 30px gutters --- .../contrib/bootstrap4_grid/cms_plugins.py | 3 +-- .../0011_drop_field_spacing_horizontal.py | 20 +++++++++++++++++++ .../contrib/bootstrap4_grid/models.py | 8 +------- 3 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0011_drop_field_spacing_horizontal.py diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index 92efa9d3..5a91ed6f 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -86,7 +86,7 @@ class Bootstrap4GridRowPlugin(CMSPluginBase): 'fields': ( 'create', ('vertical_alignment', 'horizontal_alignment'), - ('gutters_horizontal', 'gutters_vertical'), + 'gutters_vertical', ) }), (_('Advanced settings'), { @@ -121,7 +121,6 @@ def render(self, context, instance: Bootstrap4GridRow, placeholder): gutter = 'no-gutters' if instance.gutters else '' classes = concat_classes([ 'row', - f'{self.css_class}--gutters-horizontal-{instance.gutters_horizontal.value}', f'{self.css_class}--gutters-vertical-{instance.gutters_vertical.value}', instance.vertical_alignment, instance.horizontal_alignment, diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0011_drop_field_spacing_horizontal.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0011_drop_field_spacing_horizontal.py new file mode 100644 index 00000000..540e971f --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0011_drop_field_spacing_horizontal.py @@ -0,0 +1,20 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bootstrap4_grid', '0010_drop_field_spacing_vertical_type'), + ] + + operations = [ + migrations.RemoveField( + model_name='bootstrap4gridrow', + name='gutters_horizontal', + ), + migrations.AlterField( + model_name='bootstrap4gridrow', + name='gutters', + field=models.BooleanField(default=False, help_text='Removes the horizontal spacing between the columns.', verbose_name='Remove gutters'), + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index 379d46c6..f0148285 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -112,16 +112,10 @@ class Bootstrap4GridRow(CMSPlugin): max_length=32, help_text=_("Vertical spacing between the columns inside"), ) - gutters_horizontal = EnumField( - GuttersHorizontal, - default=GuttersHorizontal.NORMAL, - max_length=32, - help_text=_("Horizontal spacing between the columns inside"), - ) gutters = models.BooleanField( verbose_name=_('Remove gutters'), default=False, - help_text=_('Removes the marginal gutters from the grid.'), + help_text=_('Removes the horizontal spacing between the columns.'), ) tag_type = TagTypeField() attributes = AttributesField() From 1c3af865b1d4a73037b25ead808f7a9e9f3e8d4b Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Mon, 15 Jun 2020 22:18:55 +0300 Subject: [PATCH 19/36] container: add width internal field --- .../contrib/bootstrap4_grid/cms_plugins.py | 5 +++ .../contrib/bootstrap4_grid/constants.py | 11 ++++++ .../0012_add_field_width_internal.py | 37 +++++++++++++++++++ .../contrib/bootstrap4_grid/models.py | 30 +++++++++++++-- .../djangocms_bootstrap4/grid_container.html | 8 ++-- 5 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0012_add_field_width_internal.py diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index 5a91ed6f..d774bfea 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -34,6 +34,7 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): 'fields': ( 'name', 'container_type', + 'width_internal', 'background', 'spacing_vertical', ) @@ -57,6 +58,10 @@ def render(self, context, instance: Bootstrap4GridContainer, placeholder): ]) instance.attributes['class'] = classes + instance.attributes['data-type'] = instance.container_type.value + instance.attributes['data-width-internal'] = instance.width_internal.value + instance.attributes['data-spacing-vertical'] = instance.spacing_vertical.value + return super().render(context, instance, placeholder) @classmethod diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py index 0280b37d..eb178b7e 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py @@ -31,6 +31,17 @@ class GridContainerType(Enum): ) +class GridContainerWidthInternal(Enum): + FULL_WIDTH = 'full-width' + + +GRID_CONTAINER_WIDTH_INTERNAL: GridContainerWidthInternal = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_GRID_CONTAINER_WIDTH_INTERNAL', + GridContainerWidthInternal, +) + + class GridContainerBackground(Enum): """ contains css classes diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0012_add_field_width_internal.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0012_add_field_width_internal.py new file mode 100644 index 00000000..5283a5fb --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0012_add_field_width_internal.py @@ -0,0 +1,37 @@ +# Generated by Django 2.2.13 on 2020-06-15 18:29 + +from django.db import migrations +import djangocms_bootstrap4.contrib.bootstrap4_grid.constants +import djangocms_bootstrap4.contrib.bootstrap4_grid.models +import enumfields.fields +import settings + + +class Migration(migrations.Migration): + dependencies = [ + ('bootstrap4_grid', '0011_drop_field_spacing_horizontal'), + ] + + operations = [ + migrations.AddField( + model_name='bootstrap4gridcontainer', + name='width_internal', + field=enumfields.fields.EnumField( + default='full-width', + enum=djangocms_bootstrap4.contrib.bootstrap4_grid.constants.GridContainerWidthInternal, + help_text='You can change it eg if you want to have a full-width gray background, but a limited content width within that background', + max_length=255, + verbose_name='Internal width', + ), + ), + migrations.AlterField( + model_name='bootstrap4gridcontainer', + name='container_type', + field=enumfields.fields.EnumField( + default='container', + enum=djangocms_bootstrap4.contrib.bootstrap4_grid.constants.GridContainerType, + max_length=255, + verbose_name='External width', + ), + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index f0148285..caf75d96 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -18,6 +18,7 @@ from .constants import GRID_CONTAINER_BACKGROUND from .constants import GRID_CONTAINER_SPACING from .constants import GRID_CONTAINER_TYPE +from .constants import GRID_CONTAINER_WIDTH_INTERNAL from .constants import GRID_ROW_HORIZONTAL_ALIGNMENT_CHOICES from .constants import GRID_ROW_VERTICAL_ALIGNMENT_CHOICES from .constants import GRID_SIZE @@ -37,9 +38,19 @@ class Bootstrap4GridContainer(CMSPlugin): container_type = EnumField( GRID_CONTAINER_TYPE, default=GRID_CONTAINER_TYPE.DYNAMIC_WIDTH, - verbose_name=_('Container width'), + verbose_name=_('External width'), max_length=255, ) + width_internal = EnumField( + GRID_CONTAINER_WIDTH_INTERNAL, + default=GRID_CONTAINER_WIDTH_INTERNAL.FULL_WIDTH, + verbose_name=_('Internal width'), + max_length=255, + help_text=_( + 'You can change it eg if you want to have a full-width ' + 'gray background, but a limited content width within that background' + ) + ) background = EnumField( GRID_CONTAINER_BACKGROUND, default=GRID_CONTAINER_BACKGROUND.NONE, @@ -59,10 +70,21 @@ def __str__(self) -> str: return str(self.pk) def get_short_description(self) -> str: + desc: str = '' if self.name: - return self.name - else: - return f'({self.container_type.label})' + desc += f'{self.name} ' + + is_width_internal_selected = self.width_internal != self._meta.get_field('width_internal').get_default() + is_background_selected = self.background != self._meta.get_field('background').get_default() + if is_background_selected or is_width_internal_selected: + desc += '[' + if is_background_selected: + desc += str(self.background) + if is_width_internal_selected: + desc += str(self.width_internal) + desc += ']' + + return desc class GuttersVertical(Enum): diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/templates/djangocms_bootstrap4/grid_container.html b/djangocms_bootstrap4/contrib/bootstrap4_grid/templates/djangocms_bootstrap4/grid_container.html index a490dfc9..0abd2f09 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/templates/djangocms_bootstrap4/grid_container.html +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/templates/djangocms_bootstrap4/grid_container.html @@ -1,7 +1,9 @@ {% load cms_tags %} <{{ instance.tag_type }} {{ instance.attributes_str }}> - {% for plugin in instance.child_plugin_instances %} - {% with forloop as parentloop %}{% render_plugin plugin %}{% endwith %} - {% endfor %} +
+ {% for plugin in instance.child_plugin_instances %} + {% with forloop as parentloop %}{% render_plugin plugin %}{% endwith %} + {% endfor %} +
From 2adee946967523aedd6eb1751ab04142ae88ce42 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Mon, 15 Jun 2020 22:57:40 +0300 Subject: [PATCH 20/36] container: improve cms short description --- djangocms_bootstrap4/contrib/bootstrap4_grid/models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index caf75d96..6cdc192b 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -78,9 +78,11 @@ def get_short_description(self) -> str: is_background_selected = self.background != self._meta.get_field('background').get_default() if is_background_selected or is_width_internal_selected: desc += '[' - if is_background_selected: + if is_background_selected and is_width_internal_selected: + desc += f'{self.background}, {self.width_internal}' + elif is_background_selected: desc += str(self.background) - if is_width_internal_selected: + elif is_width_internal_selected: desc += str(self.width_internal) desc += ']' From 0b5b37d61c1e96cad898cdb8e2816738373366fa Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Mon, 15 Jun 2020 23:19:17 +0300 Subject: [PATCH 21/36] container: remove container type from admin as it isn't required --- djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py | 1 - djangocms_bootstrap4/contrib/bootstrap4_grid/models.py | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index d774bfea..2ff68fc5 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -33,7 +33,6 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): (None, { 'fields': ( 'name', - 'container_type', 'width_internal', 'background', 'spacing_vertical', diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index 6cdc192b..0a5ece2f 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -44,12 +44,8 @@ class Bootstrap4GridContainer(CMSPlugin): width_internal = EnumField( GRID_CONTAINER_WIDTH_INTERNAL, default=GRID_CONTAINER_WIDTH_INTERNAL.FULL_WIDTH, - verbose_name=_('Internal width'), + verbose_name=_('Internal content width'), max_length=255, - help_text=_( - 'You can change it eg if you want to have a full-width ' - 'gray background, but a limited content width within that background' - ) ) background = EnumField( GRID_CONTAINER_BACKGROUND, From 877b9e310bde5a8da8a7e98e55f554d082d03e41 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Tue, 16 Jun 2020 10:46:46 +0300 Subject: [PATCH 22/36] container: fix the default container type - set to full width --- ...r_field_container_type_with_new_default.py | 19 +++++++++++++++++++ .../contrib/bootstrap4_grid/models.py | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0013_alter_field_container_type_with_new_default.py diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0013_alter_field_container_type_with_new_default.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0013_alter_field_container_type_with_new_default.py new file mode 100644 index 00000000..faea907c --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0013_alter_field_container_type_with_new_default.py @@ -0,0 +1,19 @@ +from django.db import migrations +import djangocms_bootstrap4.contrib.bootstrap4_grid.models +import djangocms_bootstrap4.contrib.bootstrap4_grid.constants +import enumfields.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('bootstrap4_grid', '0012_add_field_width_internal'), + ] + + operations = [ + migrations.AlterField( + model_name='bootstrap4gridcontainer', + name='container_type', + field=enumfields.fields.EnumField(default='container-fluid', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.constants.GridContainerType, max_length=255, verbose_name='External width'), + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index 0a5ece2f..1724d4c7 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -37,7 +37,7 @@ class Bootstrap4GridContainer(CMSPlugin): ) container_type = EnumField( GRID_CONTAINER_TYPE, - default=GRID_CONTAINER_TYPE.DYNAMIC_WIDTH, + default=GRID_CONTAINER_TYPE.FULL_WIDTH, verbose_name=_('External width'), max_length=255, ) From be03e751472fcbc9273a5745298c359e3e21618b Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Mon, 6 Jul 2020 13:57:48 +0300 Subject: [PATCH 23/36] container: allow fieldsets customization --- .../contrib/bootstrap4_grid/cms_plugins.py | 20 ++------------- .../contrib/bootstrap4_grid/constants.py | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index 2ff68fc5..d403f97f 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -9,6 +9,7 @@ from cms.plugin_pool import plugin_pool from djangocms_bootstrap4.constants import DEVICE_SIZES +from djangocms_bootstrap4.contrib.bootstrap4_grid.constants import GRID_CONTAINER_FIELDSETS from djangocms_bootstrap4.helpers import concat_classes from .forms import Bootstrap4GridColumnForm, Bootstrap4GridRowForm @@ -28,24 +29,7 @@ class Bootstrap4GridContainerPlugin(CMSPluginBase): render_template = 'djangocms_bootstrap4/grid_container.html' allow_children = True css_class = 'container-plugin' - - fieldsets = [ - (None, { - 'fields': ( - 'name', - 'width_internal', - 'background', - 'spacing_vertical', - ) - }), - (_('Advanced settings'), { - 'classes': ('collapse',), - 'fields': ( - 'tag_type', - 'attributes', - ) - }), - ] + fieldsets = GRID_CONTAINER_FIELDSETS def render(self, context, instance: Bootstrap4GridContainer, placeholder): classes = concat_classes([ diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py index eb178b7e..70e00e3e 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py @@ -31,6 +31,31 @@ class GridContainerType(Enum): ) +container_fieldsets_default = [ + (None, { + 'fields': ( + 'name', + 'width_internal', + 'background', + 'spacing_vertical', + ), + }), + (_('Advanced settings'), { + 'classes': ['collapse'], + 'fields': ( + 'tag_type', + 'attributes', + ), + }), +] + +GRID_CONTAINER_FIELDSETS = getattr( + settings, + 'DJANGOCMS_BOOTSTRAP4_GRID_CONTAINER_FIELDSETS', + container_fieldsets_default, +) + + class GridContainerWidthInternal(Enum): FULL_WIDTH = 'full-width' From 44dcf0b2f6aac544cf6984c1a42faac50c31fb3a Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sat, 1 Aug 2020 17:02:02 +0300 Subject: [PATCH 24/36] heading: move it out of
--- .../djangocms_bootstrap4/heading.html | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html b/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html index d76b087c..73ad9431 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html +++ b/djangocms_bootstrap4/contrib/bootstrap4_heading/templates/djangocms_bootstrap4/heading.html @@ -1,19 +1,10 @@ {% load cms_tags menu_tags %} -
- <{{ instance.tag.value }} - class=" - heading-plugin - heading-plugin--{{ instance.type.value }} - heading-plugin--color-{{ instance.color.value }} - text-{{ instance.alignment.value }} - " - style=" - {% if instance.size %}font-size: {{ instance.size }}{{ instance.size_unit.value }}{% endif %} - " - id="{{ instance.get_anchor }}" - > - {{ instance.name|linebreaksbr }} - -
+<{{ instance.tag.value }} + class="heading-plugin heading-plugin--{{ instance.type.value }} heading-plugin--color-{{ instance.color.value }} text-{{ instance.alignment.value }}" + style="{% if instance.size %}font-size: {{ instance.size }}{{ instance.size_unit.value }}{% endif %}" + id="{{ instance.get_anchor }}" +> + {{ instance.name|linebreaksbr }} + From 1889ec49c002926c62d1a939018916cd16ff81b5 Mon Sep 17 00:00:00 2001 From: Victor Yunenko Date: Sun, 2 Aug 2020 12:16:39 +0300 Subject: [PATCH 25/36] grid: allow to center column content --- .../contrib/bootstrap4_grid/cms_plugins.py | 9 ++- .../contrib/bootstrap4_grid/constants.py | 7 ++ ...dd_field_horizontal_alignment_to_column.py | 37 ++++++++++ .../migrations/0015_alter_metadata.py | 23 ++++++ .../contrib/bootstrap4_grid/models.py | 8 ++- .../djangocms_bootstrap4/js/bundle.base.js | 2 +- .../djangocms_bootstrap4/js/bundle.grid.js | 2 +- package.json | 71 ++++++++++--------- private/js/grid.js | 6 ++ 9 files changed, 125 insertions(+), 40 deletions(-) create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0014_add_field_horizontal_alignment_to_column.py create mode 100644 djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0015_alter_metadata.py diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py index d403f97f..416d3cb9 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/cms_plugins.py @@ -141,9 +141,11 @@ class Bootstrap4GridColumnPlugin(CMSPluginBase): fieldsets = [ (None, { - 'fields': ( - ('column_type', 'column_alignment'), - ) + 'fields': [ + 'column_type', + 'column_alignment', + 'horizontal_alignment', + ], }), (_('Responsive settings'), { 'fields': ( @@ -174,6 +176,7 @@ def render(self, context, instance, placeholder): instance.column_type, column, instance.column_alignment, + instance.horizontal_alignment, instance.attributes.get('class'), ]) instance.attributes['class'] = attr_classes diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py index 70e00e3e..f1c444e1 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/constants.py @@ -117,6 +117,13 @@ class GridContainerSpacing(Enum): ('align-self-end', _('Align self end')), ) +GRID_COLUMN_HORIZONTAL_ALIGNMENT_CHOICES = ( + ('align-items-start', _('Align items start')), + ('align-items-center', _('Align items center')), + ('align-items-end', _('Align items end')), + ('align-items-stretch', _('Align items stretch')), +) + GRID_COLUMN_CHOICES = getattr( settings, 'DJANGOCMS_BOOTSTRAP4_GRID_COLUMN_CHOICES', diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0014_add_field_horizontal_alignment_to_column.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0014_add_field_horizontal_alignment_to_column.py new file mode 100644 index 00000000..521f6573 --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0014_add_field_horizontal_alignment_to_column.py @@ -0,0 +1,37 @@ +# Generated by Django 2.2.14 on 2020-08-02 09:11 + +from django.db import migrations, models +import djangocms_bootstrap4.contrib.bootstrap4_grid.models +import enumfields.fields +import settings + + +class Migration(migrations.Migration): + + dependencies = [ + ('bootstrap4_grid', '0013_alter_field_container_type_with_new_default'), + ] + + operations = [ + migrations.AddField( + model_name='bootstrap4gridcolumn', + name='horizontal_alignment', + field=models.CharField(choices=[('align-items-start', 'Align items start'), ('align-items-center', 'Align items center'), ('align-items-end', 'Align items end'), ('align-items-stretch', 'Align items stretch')], default='align-items-start', help_text='Read more in the documentation.', max_length=255, verbose_name='Horizontal alignment'), + preserve_default=False, + ), + migrations.AlterField( + model_name='bootstrap4gridcontainer', + name='spacing_vertical', + field=enumfields.fields.EnumField(default='none', enum=settings.GridContainerSpacing, max_length=255, verbose_name='Vertical spacing'), + ), + migrations.AlterField( + model_name='bootstrap4gridcontainer', + name='width_internal', + field=enumfields.fields.EnumField(default='full-width', enum=settings.GridContainerWidthInternal, max_length=255, verbose_name='Internal content width'), + ), + migrations.AlterField( + model_name='bootstrap4gridrow', + name='gutters_vertical', + field=enumfields.fields.EnumField(default='none', enum=djangocms_bootstrap4.contrib.bootstrap4_grid.models.GuttersVertical, help_text='Vertical spacing between the columns inside', max_length=32), + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0015_alter_metadata.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0015_alter_metadata.py new file mode 100644 index 00000000..c3ca7c47 --- /dev/null +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/migrations/0015_alter_metadata.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.14 on 2020-08-02 09:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bootstrap4_grid', '0014_add_field_horizontal_alignment_to_column'), + ] + + operations = [ + migrations.AlterField( + model_name='bootstrap4gridcolumn', + name='column_alignment', + field=models.CharField(blank=True, choices=[('align-self-start', 'Align self start'), ('align-self-center', 'Align self center'), ('align-self-end', 'Align self end')], max_length=255, verbose_name='Vertical alignment'), + ), + migrations.AlterField( + model_name='bootstrap4gridcolumn', + name='horizontal_alignment', + field=models.CharField(choices=[('align-items-start', 'Align items start'), ('align-items-center', 'Align items center'), ('align-items-end', 'Align items end'), ('align-items-stretch', 'Align items stretch')], max_length=255, verbose_name='Horizontal alignment'), + ), + ] diff --git a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py index 1724d4c7..f95263cb 100644 --- a/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py +++ b/djangocms_bootstrap4/contrib/bootstrap4_grid/models.py @@ -4,6 +4,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext +from djangocms_bootstrap4.contrib.bootstrap4_grid.constants import GRID_COLUMN_HORIZONTAL_ALIGNMENT_CHOICES from enumfields import Enum from enumfields import EnumField from six import python_2_unicode_compatible @@ -168,11 +169,16 @@ class Bootstrap4GridColumn(CMSPlugin): max_length=255, ) column_alignment = models.CharField( - verbose_name=_('Alignment'), + verbose_name=_('Vertical alignment'), choices=GRID_COLUMN_ALIGNMENT_CHOICES, blank=True, max_length=255, ) + horizontal_alignment = models.CharField( + verbose_name=_('Horizontal alignment'), + choices=GRID_COLUMN_HORIZONTAL_ALIGNMENT_CHOICES, + max_length=255, + ) tag_type = TagTypeField() attributes = AttributesField() diff --git a/djangocms_bootstrap4/static/djangocms_bootstrap4/js/bundle.base.js b/djangocms_bootstrap4/static/djangocms_bootstrap4/js/bundle.base.js index bb73a299..3eafa693 100644 --- a/djangocms_bootstrap4/static/djangocms_bootstrap4/js/bundle.base.js +++ b/djangocms_bootstrap4/static/djangocms_bootstrap4/js/bundle.base.js @@ -1 +1 @@ -!function(e){function __webpack_require__(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,__webpack_require__),r.l=!0,r.exports}var t=window.webpackJsonp;window.webpackJsonp=function(n,o,i){for(var s,a,u,c=0,l=[];c0&&t-1 in e)}function nodeName(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}function winnow(e,t,n){return b(t)?T.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?T.grep(e,function(e){return e===t!==n}):"string"!=typeof t?T.grep(e,function(e){return p.call(t,e)>-1!==n}):T.filter(t,e,n)}function sibling(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}function createOptions(e){var t={};return T.each(e.match(P)||[],function(e,n){t[n]=!0}),t}function Identity(e){return e}function Thrower(e){throw e}function adoptValue(e,t,n,r){var o;try{e&&b(o=e.promise)?o.call(e).done(t).fail(n):e&&b(o=e.then)?o.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}function completed(){a.removeEventListener("DOMContentLoaded",completed),n.removeEventListener("load",completed),T.ready()}function fcamelCase(e,t){return t.toUpperCase()}function camelCase(e){return e.replace(H,"ms-").replace(F,fcamelCase)}function Data(){this.expando=T.expando+Data.uid++}function getData(e){return"true"===e||"false"!==e&&("null"===e?null:e===+e+""?+e:W.test(e)?JSON.parse(e):e)}function dataAttr(e,t,n){var r;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(B,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n=getData(n)}catch(e){}I.set(e,t,n)}else n=void 0;return n}function adjustCSS(e,t,n,r){var o,i,s=20,a=r?function(){return r.cur()}:function(){return T.css(e,t,"")},u=a(),c=n&&n[3]||(T.cssNumber[t]?"":"px"),l=e.nodeType&&(T.cssNumber[t]||"px"!==c&&+u)&&G.exec(T.css(e,t));if(l&&l[3]!==c){for(u/=2,c=c||l[3],l=+u||1;s--;)T.style(e,t,l+c),(1-i)*(1-(i=a()/u||.5))<=0&&(s=0),l/=i;l*=2,T.style(e,t,l+c),n=n||[]}return n&&(l=+l||+u||0,o=n[1]?l+(n[1]+1)*n[2]:+n[2],r&&(r.unit=c,r.start=l,r.end=o)),o}function getDefaultDisplay(e){var t,n=e.ownerDocument,r=e.nodeName,o=K[r];return o||(t=n.body.appendChild(n.createElement(r)),o=T.css(t,"display"),t.parentNode.removeChild(t),"none"===o&&(o="block"),K[r]=o,o)}function showHide(e,t){for(var n,r,o=[],i=0,s=e.length;i-1)o&&o.push(i);else if(c=X(i),s=getAll(f.appendChild(i),"script"),c&&setGlobalEval(s),n)for(l=0;i=s[l++];)te.test(i.type||"")&&n.push(i);return f}function returnTrue(){return!0}function returnFalse(){return!1}function expectSync(e,t){return e===safeActiveElement()==("focus"===t)}function safeActiveElement(){try{return a.activeElement}catch(e){}}function on(e,t,n,r,o,i){var s,a;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(a in t)on(e,a,n,r,t[a],i);return e}if(null==r&&null==o?(o=n,r=n=void 0):null==o&&("string"==typeof n?(o=r,r=void 0):(o=r,r=n,n=void 0)),!1===o)o=returnFalse;else if(!o)return e;return 1===i&&(s=o,o=function(e){return T().off(e),s.apply(this,arguments)},o.guid=s.guid||(s.guid=T.guid++)),e.each(function(){T.event.add(this,t,o,r,n)})}function leverageNative(e,t,n){if(!n)return void(void 0===R.get(e,t)&&T.event.add(e,t,returnTrue));R.set(e,t,!1),T.event.add(e,t,{namespace:!1,handler:function(e){var r,o,i=R.get(this,t);if(1&e.isTrigger&&this[t]){if(i.length)(T.event.special[t]||{}).delegateType&&e.stopPropagation();else if(i=c.call(arguments),R.set(this,t,i),r=n(this,t),this[t](),o=R.get(this,t),i!==o||r?R.set(this,t,!1):o={},i!==o)return e.stopImmediatePropagation(),e.preventDefault(),o.value}else i.length&&(R.set(this,t,{value:T.event.trigger(T.extend(i[0],T.Event.prototype),i.slice(1),this)}),e.stopImmediatePropagation())}})}function manipulationTarget(e,t){return nodeName(e,"table")&&nodeName(11!==t.nodeType?t:t.firstChild,"tr")?T(e).children("tbody")[0]||e:e}function disableScript(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function restoreScript(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function cloneCopyEvent(e,t){var n,r,o,i,s,a,u,c;if(1===t.nodeType){if(R.hasData(e)&&(i=R.access(e),s=R.set(t,i),c=i.events)){delete s.handle,s.events={};for(o in c)for(n=0,r=c[o].length;n1&&"string"==typeof h&&!y.checkClone&&ce.test(h))return e.each(function(o){var i=e.eq(o);v&&(t[0]=h.call(this,o,i.html())),domManip(i,t,n,r)});if(p&&(o=buildFragment(t,e[0].ownerDocument,!1,e,r),i=o.firstChild,1===o.childNodes.length&&(o=i),i||r)){for(s=T.map(getAll(o,"script"),disableScript),a=s.length;f=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-i-u-a-.5))||0),u}function getWidthOrHeight(e,t,n){var r=pe(e),o=!y.boxSizingReliable()||n,i=o&&"border-box"===T.css(e,"boxSizing",!1,r),s=i,a=curCSS(e,t,r),u="offset"+t[0].toUpperCase()+t.slice(1);if(fe.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||"auto"===a||!parseFloat(a)&&"inline"===T.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===T.css(e,"boxSizing",!1,r),(s=u in e)&&(a=e[u])),(a=parseFloat(a)||0)+boxModelAdjustment(e,t,n||(i?"border":"content"),s,r,a)+"px"}function Tween(e,t,n,r,o){return new Tween.prototype.init(e,t,n,r,o)}function schedule(){Te&&(!1===a.hidden&&n.requestAnimationFrame?n.requestAnimationFrame(schedule):n.setTimeout(schedule,T.fx.interval),T.fx.tick())}function createFxNow(){return n.setTimeout(function(){we=void 0}),we=Date.now()}function genFx(e,t){var n,r=0,o={height:e};for(t=t?1:0;r<4;r+=2-t)n=V[r],o["margin"+n]=o["padding"+n]=e;return t&&(o.opacity=o.width=e),o}function createTween(e,t,n){for(var r,o=(Animation.tweeners[t]||[]).concat(Animation.tweeners["*"]),i=0,s=o.length;i=0&&nr.cacheLength&&delete cache[e.shift()],cache[t+" "]=n}var e=[];return cache}function markFunction(e){return e[x]=!0,e}function assert(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function addHandle(e,t){for(var n=e.split("|"),o=n.length;o--;)r.attrHandle[n[o]]=t}function siblingCheck(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function createDisabledPseudo(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&se(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function createPositionalPseudo(e){return markFunction(function(t){return t=+t,markFunction(function(n,r){for(var o,i=e([],n.length,t),s=i.length;s--;)n[o=i[s]]&&(n[o]=!(r[o]=n[o]))})})}function testContext(e){return e&&void 0!==e.getElementsByTagName&&e}function setFilters(){}function toSelector(e){for(var t=0,n=e.length,r="";t1?function(t,n,r){for(var o=e.length;o--;)if(!e[o](t,n,r))return!1;return!0}:e[0]}function multipleContexts(e,t,n){for(var r=0,o=t.length;r-1&&(i[c]=!(s[c]=f))}}else m=condense(m===s?m.splice(h,m.length):m),o?o(null,s,m,u):P.apply(s,m)})}function matcherFromTokens(e){for(var t,n,o,i=e.length,s=r.relative[e[0].type],a=s||r.relative[" "],u=s?1:0,l=addCombinator(function(e){return e===t},a,!0),f=addCombinator(function(e){return q(t,e)>-1},a,!0),p=[function(e,n,r){var o=!s&&(r||n!==c)||((t=n).nodeType?l(e,n,r):f(e,n,r));return t=null,o}];u1&&elementMatcher(p),u>1&&toSelector(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(W,"$1"),n,u0,o=e.length>0,i=function(i,s,a,u,l){var f,h,g,m=0,y="0",b=i&&[],x=[],w=c,C=i||o&&r.find.TAG("*",l),S=T+=null==w?1:Math.random()||.1,k=C.length;for(l&&(c=s===d||s||l);y!==k&&null!=(f=C[y]);y++){if(o&&f){for(h=0,s||f.ownerDocument===d||(p(f),a=!v);g=e[h++];)if(g(f,s||d,a)){u.push(f);break}l&&(T=S)}n&&((f=!g&&f)&&m--,i&&b.push(f))}if(m+=y,n&&y!==m){for(h=0;g=t[h++];)g(b,x,s,a);if(i){if(m>0)for(;y--;)b[y]||x[y]||(x[y]=D.call(u));x=condense(x)}P.apply(u,x),l&&!i&&x.length>0&&m+t.length>1&&Sizzle.uniqueSort(u)}return l&&(T=S,c=w),b};return n?markFunction(i):i}var t,n,r,o,i,s,a,u,c,l,f,p,d,h,v,g,m,y,b,x="sizzle"+1*new Date,w=e.document,T=0,C=0,S=createCache(),k=createCache(),_=createCache(),j=createCache(),A=function(e,t){return e===t&&(f=!0),0},E={}.hasOwnProperty,N=[],D=N.pop,O=N.push,P=N.push,L=N.slice,q=function(e,t){for(var n=0,r=e.length;n+~]|"+H+")"+H+"*"),G=new RegExp(H+"|>"),V=new RegExp(R),U=new RegExp("^"+F+"$"),X={ID:new RegExp("^#("+F+")"),CLASS:new RegExp("^\\.("+F+")"),TAG:new RegExp("^("+F+"|[*])"),ATTR:new RegExp("^"+z),PSEUDO:new RegExp("^"+R),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+H+"*(even|odd|(([+-]|)(\\d*)n|)"+H+"*(?:([+-]|)"+H+"*(\\d+)|))"+H+"*\\)|)","i"),bool:new RegExp("^(?:"+M+")$","i"),needsContext:new RegExp("^"+H+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+H+"*((?:-\\d)?\\d*)"+H+"*\\)|)(?=[^-]|$)","i")},J=/HTML$/i,Y=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+H+"?|("+H+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,oe=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},ie=function(){p()},se=addCombinator(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{P.apply(N=L.call(w.childNodes),w.childNodes),N[w.childNodes.length].nodeType}catch(e){P={apply:N.length?function(e,t){O.apply(e,L.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}n=Sizzle.support={},i=Sizzle.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!J.test(t||n&&n.nodeName||"HTML")},p=Sizzle.setDocument=function(e){var t,o,s=e?e.ownerDocument||e:w;return s!==d&&9===s.nodeType&&s.documentElement?(d=s,h=d.documentElement,v=!i(d),w!==d&&(o=d.defaultView)&&o.top!==o&&(o.addEventListener?o.addEventListener("unload",ie,!1):o.attachEvent&&o.attachEvent("onunload",ie)),n.attributes=assert(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=assert(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=K.test(d.getElementsByClassName),n.getById=assert(function(e){return h.appendChild(e).id=x,!d.getElementsByName||!d.getElementsByName(x).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&v){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){var n=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&v){var n,r,o,i=t.getElementById(e);if(i){if((n=i.getAttributeNode("id"))&&n.value===e)return[i];for(o=t.getElementsByName(e),r=0;i=o[r++];)if((n=i.getAttributeNode("id"))&&n.value===e)return[i]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],o=0,i=t.getElementsByTagName(e);if("*"===e){for(;n=i[o++];)1===n.nodeType&&r.push(n);return r}return i},r.find.CLASS=n.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&v)return t.getElementsByClassName(e)},m=[],g=[],(n.qsa=K.test(d.querySelectorAll))&&(assert(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&g.push("[*^$]="+H+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||g.push("\\["+H+"*(?:value|"+M+")"),e.querySelectorAll("[id~="+x+"-]").length||g.push("~="),e.querySelectorAll(":checked").length||g.push(":checked"),e.querySelectorAll("a#"+x+"+*").length||g.push(".#.+[+~]")}),assert(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&g.push("name"+H+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&g.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(n.matchesSelector=K.test(y=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&assert(function(e){n.disconnectedMatch=y.call(e,"*"),y.call(e,"[s!='']:x"),m.push("!=",R)}),g=g.length&&new RegExp(g.join("|")),m=m.length&&new RegExp(m.join("|")),t=K.test(h.compareDocumentPosition),b=t||K.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},A=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&r||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&b(w,e)?-1:t===d||t.ownerDocument===w&&b(w,t)?1:l?q(l,e)-q(l,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,o=e.parentNode,i=t.parentNode,s=[e],a=[t];if(!o||!i)return e===d?-1:t===d?1:o?-1:i?1:l?q(l,e)-q(l,t):0;if(o===i)return siblingCheck(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)a.unshift(n);for(;s[r]===a[r];)r++;return r?siblingCheck(s[r],a[r]):s[r]===w?-1:a[r]===w?1:0},d):d},Sizzle.matches=function(e,t){return Sizzle(e,null,null,t)},Sizzle.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),n.matchesSelector&&v&&!j[t+" "]&&(!m||!m.test(t))&&(!g||!g.test(t)))try{var r=y.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){j(t,!0)}return Sizzle(t,d,null,[e]).length>0},Sizzle.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),b(e,t)},Sizzle.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var o=r.attrHandle[t.toLowerCase()],i=o&&E.call(r.attrHandle,t.toLowerCase())?o(e,t,!v):void 0;return void 0!==i?i:n.attributes||!v?e.getAttribute(t):(i=e.getAttributeNode(t))&&i.specified?i.value:null},Sizzle.escape=function(e){return(e+"").replace(re,oe)},Sizzle.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},Sizzle.uniqueSort=function(e){var t,r=[],o=0,i=0;if(f=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(A),f){for(;t=e[i++];)t===e[i]&&(o=r.push(i));for(;o--;)e.splice(r[o],1)}return l=null,e},o=Sizzle.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=o(t);return n},r=Sizzle.selectors={cacheLength:50,createPseudo:markFunction,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||Sizzle.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&Sizzle.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return X.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&V.test(n)&&(t=s(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=S[e+" "];return t||(t=new RegExp("(^|"+H+")"+e+"("+H+"|$)"))&&S(e,function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var o=Sizzle.attr(r,e);return null==o?"!="===t:!t||(o+="","="===t?o===n:"!="===t?o!==n:"^="===t?n&&0===o.indexOf(n):"*="===t?n&&o.indexOf(n)>-1:"$="===t?n&&o.slice(-n.length)===n:"~="===t?(" "+o.replace(I," ")+" ").indexOf(n)>-1:"|="===t&&(o===n||o.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,o){var i="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===o?function(e){return!!e.parentNode}:function(t,n,u){var c,l,f,p,d,h,v=i!==s?"nextSibling":"previousSibling",g=t.parentNode,m=a&&t.nodeName.toLowerCase(),y=!u&&!a,b=!1;if(g){if(i){for(;v;){for(p=t;p=p[v];)if(a?p.nodeName.toLowerCase()===m:1===p.nodeType)return!1;h=v="only"===e&&!h&&"nextSibling"}return!0}if(h=[s?g.firstChild:g.lastChild],s&&y){for(p=g,f=p[x]||(p[x]={}),l=f[p.uniqueID]||(f[p.uniqueID]={}),c=l[e]||[],d=c[0]===T&&c[1],b=d&&c[2],p=d&&g.childNodes[d];p=++d&&p&&p[v]||(b=d=0)||h.pop();)if(1===p.nodeType&&++b&&p===t){l[e]=[T,d,b];break}}else if(y&&(p=t,f=p[x]||(p[x]={}),l=f[p.uniqueID]||(f[p.uniqueID]={}),c=l[e]||[],d=c[0]===T&&c[1],b=d),!1===b)for(;(p=++d&&p&&p[v]||(b=d=0)||h.pop())&&((a?p.nodeName.toLowerCase()!==m:1!==p.nodeType)||!++b||(y&&(f=p[x]||(p[x]={}),l=f[p.uniqueID]||(f[p.uniqueID]={}),l[e]=[T,b]),p!==t)););return(b-=o)===r||b%r==0&&b/r>=0}}},PSEUDO:function(e,t){var n,o=r.pseudos[e]||r.setFilters[e.toLowerCase()]||Sizzle.error("unsupported pseudo: "+e);return o[x]?o(t):o.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?markFunction(function(e,n){for(var r,i=o(e,t),s=i.length;s--;)r=q(e,i[s]),e[r]=!(n[r]=i[s])}):function(e){return o(e,0,n)}):o}},pseudos:{not:markFunction(function(e){var t=[],n=[],r=a(e.replace(W,"$1"));return r[x]?markFunction(function(e,t,n,o){for(var i,s=r(e,null,o,[]),a=e.length;a--;)(i=s[a])&&(e[a]=!(t[a]=i))}):function(e,o,i){return t[0]=e,r(t,null,i,n),t[0]=null,!n.pop()}}),has:markFunction(function(e){return function(t){return Sizzle(e,t).length>0}}),contains:markFunction(function(e){return e=e.replace(te,ne),function(t){return(t.textContent||o(t)).indexOf(e)>-1}}),lang:markFunction(function(e){return U.test(e||"")||Sizzle.error("unsupported lang: "+e),e=e.replace(te,ne).toLowerCase(),function(t){var n;do{if(n=v?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:createDisabledPseudo(!1),disabled:createDisabledPseudo(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return Y.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:createPositionalPseudo(function(){return[0]}),last:createPositionalPseudo(function(e,t){return[t-1]}),eq:createPositionalPseudo(function(e,t,n){return[n<0?n+t:n]}),even:createPositionalPseudo(function(e,t){for(var n=0;nt?t:n;--r>=0;)e.push(r);return e}),gt:createPositionalPseudo(function(e,t,n){for(var r=n<0?n+t:n;++r2&&"ID"===(c=u[0]).type&&9===t.nodeType&&v&&r.relative[u[1].type]){if(!(t=(r.find.ID(c.matches[0].replace(te,ne),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}for(i=X.needsContext.test(e)?0:u.length;i--&&(c=u[i],!r.relative[l=c.type]);)if((f=r.find[l])&&(o=f(c.matches[0].replace(te,ne),ee.test(u[0].type)&&testContext(t.parentNode)||t))){if(u.splice(i,1),!(e=o.length&&toSelector(u)))return P.apply(n,o),n;break}}return(p||a(e,d))(o,t,!v,n,!t||ee.test(e)&&testContext(t.parentNode)||t),n},n.sortStable=x.split("").sort(A).join("")===x,n.detectDuplicates=!!f,p(),n.sortDetached=assert(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),assert(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||addHandle("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&assert(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||addHandle("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),assert(function(e){return null==e.getAttribute("disabled")})||addHandle(M,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),Sizzle}(n);T.find=S,T.expr=S.selectors,T.expr[":"]=T.expr.pseudos,T.uniqueSort=T.unique=S.uniqueSort,T.text=S.getText,T.isXMLDoc=S.isXML,T.contains=S.contains,T.escapeSelector=S.escape;var k=function(e,t,n){for(var r=[],o=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(o&&T(e).is(n))break;r.push(e)}return r},_=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},j=T.expr.match.needsContext,A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;T.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?T.find.matchesSelector(r,e)?[r]:[]:T.find.matches(e,T.grep(t,function(e){return 1===e.nodeType}))},T.fn.extend({find:function(e){var t,n,r=this.length,o=this;if("string"!=typeof e)return this.pushStack(T(e).filter(function(){for(t=0;t1?T.uniqueSort(n):n},filter:function(e){return this.pushStack(winnow(this,e||[],!1))},not:function(e){return this.pushStack(winnow(this,e||[],!0))},is:function(e){return!!winnow(this,"string"==typeof e&&j.test(e)?T(e):e||[],!1).length}});var E,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(T.fn.init=function(e,t,n){var r,o;if(!e)return this;if(n=n||E,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:N.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof T?t[0]:t,T.merge(this,T.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:a,!0)),A.test(r[1])&&T.isPlainObject(t))for(r in t)b(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return o=a.getElementById(r[2]),o&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):b(e)?void 0!==n.ready?n.ready(e):e(T):T.makeArray(e,this)}).prototype=T.fn,E=T(a);var D=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};T.fn.extend({has:function(e){var t=T(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&T.find.matchesSelector(n,e))){i.push(n);break}return this.pushStack(i.length>1?T.uniqueSort(i):i)},index:function(e){return e?"string"==typeof e?p.call(T(e),this[0]):p.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(T.uniqueSort(T.merge(this.get(),T(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),T.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return sibling(e,"nextSibling")},prev:function(e){return sibling(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return _((e.parentNode||{}).firstChild,e)},children:function(e){return _(e.firstChild)},contents:function(e){return void 0!==e.contentDocument?e.contentDocument:(nodeName(e,"template")&&(e=e.content||e),T.merge([],e.childNodes))}},function(e,t){T.fn[e]=function(n,r){var o=T.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(o=T.filter(r,o)),this.length>1&&(O[e]||T.uniqueSort(o),D.test(e)&&o.reverse()),this.pushStack(o)}});var P=/[^\x20\t\r\n\f]+/g;T.Callbacks=function(e){e="string"==typeof e?createOptions(e):T.extend({},e);var t,n,r,o,i=[],s=[],a=-1,u=function(){for(o=o||e.once,r=t=!0;s.length;a=-1)for(n=s.shift();++a-1;)i.splice(n,1),n<=a&&a--}),this},has:function(e){return e?T.inArray(e,i)>-1:i.length>0},empty:function(){return i&&(i=[]),this},disable:function(){return o=s=[],i=n="",this},disabled:function(){return!i},lock:function(){return o=s=[],n||t||(i=n=""),this},locked:function(){return!!o},fireWith:function(e,n){return o||(n=n||[],n=[e,n.slice?n.slice():n],s.push(n),t||u()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},T.extend({Deferred:function(e){var t=[["notify","progress",T.Callbacks("memory"),T.Callbacks("memory"),2],["resolve","done",T.Callbacks("once memory"),T.Callbacks("once memory"),0,"resolved"],["reject","fail",T.Callbacks("once memory"),T.Callbacks("once memory"),1,"rejected"]],r="pending",o={state:function(){return r},always:function(){return i.done(arguments).fail(arguments),this},catch:function(e){return o.then(null,e)},pipe:function(){var e=arguments;return T.Deferred(function(n){T.each(t,function(t,r){var o=b(e[r[4]])&&e[r[4]];i[r[1]](function(){var e=o&&o.apply(this,arguments);e&&b(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[r[0]+"With"](this,o?[e]:arguments)})}),e=null}).promise()},then:function(e,r,o){function resolve(e,t,r,o){return function(){var s=this,a=arguments,u=function(){var n,u;if(!(e=i&&(r!==Thrower&&(s=void 0,a=[n]),t.rejectWith(s,a))}};e?c():(T.Deferred.getStackHook&&(c.stackTrace=T.Deferred.getStackHook()),n.setTimeout(c))}}var i=0;return T.Deferred(function(n){t[0][3].add(resolve(0,n,b(o)?o:Identity,n.notifyWith)),t[1][3].add(resolve(0,n,b(e)?e:Identity)),t[2][3].add(resolve(0,n,b(r)?r:Thrower))}).promise()},promise:function(e){return null!=e?T.extend(e,o):o}},i={};return T.each(t,function(e,n){var s=n[2],a=n[5];o[n[1]]=s.add,a&&s.add(function(){r=a},t[3-e][2].disable,t[3-e][3].disable,t[0][2].lock,t[0][3].lock),s.add(n[3].fire),i[n[0]]=function(){return i[n[0]+"With"](this===i?void 0:this,arguments),this},i[n[0]+"With"]=s.fireWith}),o.promise(i),e&&e.call(i,i),i},when:function(e){var t=arguments.length,n=t,r=Array(n),o=c.call(arguments),i=T.Deferred(),s=function(e){return function(n){r[e]=this,o[e]=arguments.length>1?c.call(arguments):n,--t||i.resolveWith(r,o)}};if(t<=1&&(adoptValue(e,i.done(s(n)).resolve,i.reject,!t),"pending"===i.state()||b(o[n]&&o[n].then)))return i.then();for(;n--;)adoptValue(o[n],s(n),i.reject);return i.promise()}});var L=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;T.Deferred.exceptionHook=function(e,t){n.console&&n.console.warn&&e&&L.test(e.name)&&n.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},T.readyException=function(e){n.setTimeout(function(){throw e})};var q=T.Deferred();T.fn.ready=function(e){return q.then(e).catch(function(e){T.readyException(e)}),this},T.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--T.readyWait:T.isReady)||(T.isReady=!0,!0!==e&&--T.readyWait>0||q.resolveWith(a,[T]))}}),T.ready.then=q.then,"complete"===a.readyState||"loading"!==a.readyState&&!a.documentElement.doScroll?n.setTimeout(T.ready):(a.addEventListener("DOMContentLoaded",completed),n.addEventListener("load",completed));var M=function(e,t,n,r,o,i,s){var a=0,u=e.length,c=null==n;if("object"===toType(n)){o=!0;for(a in n)M(e,t,a,n[a],!0,i,s)}else if(void 0!==r&&(o=!0,b(r)||(s=!0),c&&(s?(t.call(e,r),t=null):(c=t,t=function(e,t,n){return c.call(T(e),n)})),t))for(;a1,null,!0)},removeData:function(e){return this.each(function(){I.remove(this,e)})}}),T.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=R.get(e,t),n&&(!r||Array.isArray(n)?r=R.access(e,t,T.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=T.queue(e,t),r=n.length,o=n.shift(),i=T._queueHooks(e,t),s=function(){T.dequeue(e,t)};"inprogress"===o&&(o=n.shift(),r--),o&&("fx"===t&&n.unshift("inprogress"),delete i.stop,o.call(e,s,i)),!r&&i&&i.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return R.get(e,n)||R.access(e,n,{empty:T.Callbacks("once memory").add(function(){R.remove(e,[t+"queue",n])})})}}),T.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]*)/i,te=/^$|^module$|\/(?:java|ecma)script/i,ne={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ne.optgroup=ne.option,ne.tbody=ne.tfoot=ne.colgroup=ne.caption=ne.thead,ne.th=ne.td;var re=/<|&#?\w+;/;!function(){var e=a.createDocumentFragment(),t=e.appendChild(a.createElement("div")),n=a.createElement("input");n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),t.appendChild(n),y.checkClone=t.cloneNode(!0).cloneNode(!0).lastChild.checked,t.innerHTML="",y.noCloneChecked=!!t.cloneNode(!0).lastChild.defaultValue}();var oe=/^key/,ie=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,se=/^([^.]*)(?:\.(.+)|)/;T.event={global:{},add:function(e,t,n,r,o){var i,s,a,u,c,l,f,p,d,h,v,g=R.get(e);if(g)for(n.handler&&(i=n,n=i.handler,o=i.selector),o&&T.find.matchesSelector(U,o),n.guid||(n.guid=T.guid++),(u=g.events)||(u=g.events={}),(s=g.handle)||(s=g.handle=function(t){return void 0!==T&&T.event.triggered!==t.type?T.event.dispatch.apply(e,arguments):void 0}),t=(t||"").match(P)||[""],c=t.length;c--;)a=se.exec(t[c])||[],d=v=a[1],h=(a[2]||"").split(".").sort(),d&&(f=T.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=T.event.special[d]||{},l=T.extend({type:d,origType:v,data:r,handler:n,guid:n.guid,selector:o,needsContext:o&&T.expr.match.needsContext.test(o),namespace:h.join(".")},i),(p=u[d])||(p=u[d]=[],p.delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,s)||e.addEventListener&&e.addEventListener(d,s)),f.add&&(f.add.call(e,l),l.handler.guid||(l.handler.guid=n.guid)),o?p.splice(p.delegateCount++,0,l):p.push(l),T.event.global[d]=!0)},remove:function(e,t,n,r,o){var i,s,a,u,c,l,f,p,d,h,v,g=R.hasData(e)&&R.get(e);if(g&&(u=g.events)){for(t=(t||"").match(P)||[""],c=t.length;c--;)if(a=se.exec(t[c])||[],d=v=a[1],h=(a[2]||"").split(".").sort(),d){for(f=T.event.special[d]||{},d=(r?f.delegateType:f.bindType)||d,p=u[d]||[],a=a[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=i=p.length;i--;)l=p[i],!o&&v!==l.origType||n&&n.guid!==l.guid||a&&!a.test(l.namespace)||r&&r!==l.selector&&("**"!==r||!l.selector)||(p.splice(i,1),l.selector&&p.delegateCount--,f.remove&&f.remove.call(e,l));s&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,g.handle)||T.removeEvent(e,d,g.handle),delete u[d])}else for(d in u)T.event.remove(e,d+t[c],n,r,!0);T.isEmptyObject(u)&&R.remove(e,"handle events")}},dispatch:function(e){var t,n,r,o,i,s,a=T.event.fix(e),u=new Array(arguments.length),c=(R.get(this,"events")||{})[a.type]||[],l=T.event.special[a.type]||{};for(u[0]=a,t=1;t=1))for(;c!==this;c=c.parentNode||this)if(1===c.nodeType&&("click"!==e.type||!0!==c.disabled)){for(i=[],s={},n=0;n-1:T.find(o,this,null,[c]).length),s[o]&&i.push(r);i.length&&a.push({elem:c,handlers:i})}return c=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,ue=/\s*$/g;T.extend({htmlPrefilter:function(e){return e.replace(ae,"<$1>")},clone:function(e,t,n){var r,o,i,s,a=e.cloneNode(!0),u=X(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||T.isXMLDoc(e)))for(s=getAll(a),i=getAll(e),r=0,o=i.length;r0&&setGlobalEval(s,!u&&getAll(e,"script")),a},cleanData:function(e){for(var t,n,r,o=T.event.special,i=0;void 0!==(n=e[i]);i++)if(z(n)){if(t=n[R.expando]){if(t.events)for(r in t.events)o[r]?T.event.remove(n,r):T.removeEvent(n,r,t.handle);n[R.expando]=void 0}n[I.expando]&&(n[I.expando]=void 0)}}}),T.fn.extend({detach:function(e){return remove(this,e,!0)},remove:function(e){return remove(this,e)},text:function(e){return M(this,function(e){return void 0===e?T.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return domManip(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){manipulationTarget(this,e).appendChild(e)}})},prepend:function(){return domManip(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=manipulationTarget(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return domManip(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return domManip(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(T.cleanData(getAll(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return T.clone(this,e,t)})},html:function(e){return M(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!ue.test(e)&&!ne[(ee.exec(e)||["",""])[1].toLowerCase()]){e=T.htmlPrefilter(e);try{for(;n1)}}),T.Tween=Tween,Tween.prototype={constructor:Tween,init:function(e,t,n,r,o,i){this.elem=e,this.prop=n,this.easing=o||T.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=i||(T.cssNumber[n]?"":"px")},cur:function(){var e=Tween.propHooks[this.prop];return e&&e.get?e.get(this):Tween.propHooks._default.get(this)},run:function(e){var t,n=Tween.propHooks[this.prop];return this.options.duration?this.pos=t=T.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Tween.propHooks._default.set(this),this}},Tween.prototype.init.prototype=Tween.prototype,Tween.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=T.css(e.elem,e.prop,""),t&&"auto"!==t?t:0)},set:function(e){T.fx.step[e.prop]?T.fx.step[e.prop](e):1!==e.elem.nodeType||!T.cssHooks[e.prop]&&null==e.elem.style[finalPropName(e.prop)]?e.elem[e.prop]=e.now:T.style(e.elem,e.prop,e.now+e.unit)}}},Tween.propHooks.scrollTop=Tween.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},T.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},T.fx=Tween.prototype.init,T.fx.step={};var we,Te,Ce=/^(?:toggle|show|hide)$/,Se=/queueHooks$/;T.Animation=T.extend(Animation,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return adjustCSS(n.elem,e,G.exec(t),n),n}]},tweener:function(e,t){b(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,o=e.length;r1)},removeAttr:function(e){return this.each(function(){T.removeAttr(this,e)})}}),T.extend({attr:function(e,t,n){var r,o,i=e.nodeType;if(3!==i&&8!==i&&2!==i)return void 0===e.getAttribute?T.prop(e,t,n):(1===i&&T.isXMLDoc(e)||(o=T.attrHooks[t.toLowerCase()]||(T.expr.match.bool.test(t)?ke:void 0)),void 0!==n?null===n?void T.removeAttr(e,t):o&&"set"in o&&void 0!==(r=o.set(e,n,t))?r:(e.setAttribute(t,n+""),n):o&&"get"in o&&null!==(r=o.get(e,t))?r:(r=T.find.attr(e,t),null==r?void 0:r))},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,o=t&&t.match(P);if(o&&1===e.nodeType)for(;n=o[r++];)e.removeAttribute(n)}}),ke={set:function(e,t,n){return!1===t?T.removeAttr(e,n):e.setAttribute(n,n),n}},T.each(T.expr.match.bool.source.match(/\w+/g),function(e,t){var n=_e[t]||T.find.attr;_e[t]=function(e,t,r){var o,i,s=t.toLowerCase();return r||(i=_e[s],_e[s]=o,o=null!=n(e,t,r)?s:null,_e[s]=i),o}});var je=/^(?:input|select|textarea|button)$/i,Ae=/^(?:a|area)$/i;T.fn.extend({prop:function(e,t){return M(this,T.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[T.propFix[e]||e]})}}),T.extend({prop:function(e,t,n){var r,o,i=e.nodeType;if(3!==i&&8!==i&&2!==i)return 1===i&&T.isXMLDoc(e)||(t=T.propFix[t]||t,o=T.propHooks[t]),void 0!==n?o&&"set"in o&&void 0!==(r=o.set(e,n,t))?r:e[t]=n:o&&"get"in o&&null!==(r=o.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=T.find.attr(e,"tabindex");return t?parseInt(t,10):je.test(e.nodeName)||Ae.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),y.optSelected||(T.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),T.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){T.propFix[this.toLowerCase()]=this}),T.fn.extend({addClass:function(e){var t,n,r,o,i,s,a,u=0;if(b(e))return this.each(function(t){T(this).addClass(e.call(this,t,getClass(this)))});if(t=classesToArray(e),t.length)for(;n=this[u++];)if(o=getClass(n),r=1===n.nodeType&&" "+stripAndCollapse(o)+" "){for(s=0;i=t[s++];)r.indexOf(" "+i+" ")<0&&(r+=i+" ");a=stripAndCollapse(r),o!==a&&n.setAttribute("class",a)}return this},removeClass:function(e){var t,n,r,o,i,s,a,u=0;if(b(e))return this.each(function(t){T(this).removeClass(e.call(this,t,getClass(this)))});if(!arguments.length)return this.attr("class","");if(t=classesToArray(e),t.length)for(;n=this[u++];)if(o=getClass(n),r=1===n.nodeType&&" "+stripAndCollapse(o)+" "){for(s=0;i=t[s++];)for(;r.indexOf(" "+i+" ")>-1;)r=r.replace(" "+i+" "," ");a=stripAndCollapse(r),o!==a&&n.setAttribute("class",a)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):b(e)?this.each(function(n){T(this).toggleClass(e.call(this,n,getClass(this),t),t)}):this.each(function(){var t,o,i,s;if(r)for(o=0,i=T(this),s=classesToArray(e);t=s[o++];)i.hasClass(t)?i.removeClass(t):i.addClass(t);else void 0!==e&&"boolean"!==n||(t=getClass(this),t&&R.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":R.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+stripAndCollapse(getClass(n))+" ").indexOf(t)>-1)return!0;return!1}});var Ee=/\r/g;T.fn.extend({val:function(e){var t,n,r,o=this[0];{if(arguments.length)return r=b(e),this.each(function(n){var o;1===this.nodeType&&(o=r?e.call(this,n,T(this).val()):e,null==o?o="":"number"==typeof o?o+="":Array.isArray(o)&&(o=T.map(o,function(e){return null==e?"":e+""})),(t=T.valHooks[this.type]||T.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,o,"value")||(this.value=o))});if(o)return(t=T.valHooks[o.type]||T.valHooks[o.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(o,"value"))?n:(n=o.value,"string"==typeof n?n.replace(Ee,""):null==n?"":n)}}}),T.extend({valHooks:{option:{get:function(e){var t=T.find.attr(e,"value");return null!=t?t:stripAndCollapse(T.text(e))}},select:{get:function(e){var t,n,r,o=e.options,i=e.selectedIndex,s="select-one"===e.type,a=s?null:[],u=s?i+1:o.length;for(r=i<0?u:s?i:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),i}}}}),T.each(["radio","checkbox"],function(){T.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=T.inArray(T(e).val(),t)>-1}},y.checkOn||(T.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in n;var Ne=/^(?:focusinfocus|focusoutblur)$/,De=function(e){e.stopPropagation()};T.extend(T.event,{trigger:function(e,t,r,o){var i,s,u,c,l,f,p,d,h=[r||a],g=v.call(e,"type")?e.type:e,m=v.call(e,"namespace")?e.namespace.split("."):[];if(s=d=u=r=r||a,3!==r.nodeType&&8!==r.nodeType&&!Ne.test(g+T.event.triggered)&&(g.indexOf(".")>-1&&(m=g.split("."),g=m.shift(),m.sort()),l=g.indexOf(":")<0&&"on"+g,e=e[T.expando]?e:new T.Event(g,"object"==typeof e&&e),e.isTrigger=o?2:3,e.namespace=m.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=r),t=null==t?[e]:T.makeArray(t,[e]),p=T.event.special[g]||{},o||!p.trigger||!1!==p.trigger.apply(r,t))){if(!o&&!p.noBubble&&!x(r)){for(c=p.delegateType||g,Ne.test(c+g)||(s=s.parentNode);s;s=s.parentNode)h.push(s),u=s;u===(r.ownerDocument||a)&&h.push(u.defaultView||u.parentWindow||n)}for(i=0;(s=h[i++])&&!e.isPropagationStopped();)d=s,e.type=i>1?c:p.bindType||g,f=(R.get(s,"events")||{})[e.type]&&R.get(s,"handle"),f&&f.apply(s,t),(f=l&&s[l])&&f.apply&&z(s)&&(e.result=f.apply(s,t),!1===e.result&&e.preventDefault());return e.type=g,o||e.isDefaultPrevented()||p._default&&!1!==p._default.apply(h.pop(),t)||!z(r)||l&&b(r[g])&&!x(r)&&(u=r[l],u&&(r[l]=null),T.event.triggered=g,e.isPropagationStopped()&&d.addEventListener(g,De),r[g](),e.isPropagationStopped()&&d.removeEventListener(g,De),T.event.triggered=void 0,u&&(r[l]=u)),e.result}},simulate:function(e,t,n){var r=T.extend(new T.Event,n,{type:e,isSimulated:!0});T.event.trigger(r,null,t)}}),T.fn.extend({trigger:function(e,t){return this.each(function(){T.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return T.event.trigger(e,t,n,!0)}}),y.focusin||T.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){T.event.simulate(t,e.target,T.event.fix(e))};T.event.special[t]={setup:function(){var r=this.ownerDocument||this,o=R.access(r,t);o||r.addEventListener(e,n,!0),R.access(r,t,(o||0)+1)},teardown:function(){var r=this.ownerDocument||this,o=R.access(r,t)-1;o?R.access(r,t,o):(r.removeEventListener(e,n,!0),R.remove(r,t))}}});var Oe=n.location,Pe=Date.now(),Le=/\?/;T.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new n.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||T.error("Invalid XML: "+e),t};var qe=/\[\]$/,Me=/\r?\n/g,He=/^(?:submit|button|image|reset|file)$/i,Fe=/^(?:input|select|textarea|keygen)/i;T.param=function(e,t){var n,r=[],o=function(e,t){var n=b(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!T.isPlainObject(e))T.each(e,function(){o(this.name,this.value)});else for(n in e)buildParams(n,e[n],t,o);return r.join("&")},T.fn.extend({serialize:function(){return T.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=T.prop(this,"elements");return e?T.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!T(this).is(":disabled")&&Fe.test(this.nodeName)&&!He.test(e)&&(this.checked||!Z.test(e))}).map(function(e,t){var n=T(this).val();return null==n?null:Array.isArray(n)?T.map(n,function(e){return{name:t.name,value:e.replace(Me,"\r\n")}}):{name:t.name,value:n.replace(Me,"\r\n")}}).get()}});var ze=/%20/g,Re=/#.*$/,Ie=/([?&])_=[^&]*/,We=/^(.*?):[ \t]*([^\r\n]*)$/gm,Be=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,$e=/^(?:GET|HEAD)$/,Ge=/^\/\//,Ve={},Ue={},Xe="*/".concat("*"),Je=a.createElement("a");Je.href=Oe.href,T.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Oe.href,type:"GET",isLocal:Be.test(Oe.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Xe,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":T.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?ajaxExtend(ajaxExtend(e,T.ajaxSettings),t):ajaxExtend(T.ajaxSettings,e)},ajaxPrefilter:addToPrefiltersOrTransports(Ve),ajaxTransport:addToPrefiltersOrTransports(Ue),ajax:function(e,t){function done(e,t,s,a){var c,p,d,x,w,C=t;l||(l=!0,u&&n.clearTimeout(u),r=void 0,i=a||"",S.readyState=e>0?4:0,c=e>=200&&e<300||304===e,s&&(x=ajaxHandleResponses(h,S,s)),x=ajaxConvert(h,x,S,c),c?(h.ifModified&&(w=S.getResponseHeader("Last-Modified"),w&&(T.lastModified[o]=w),(w=S.getResponseHeader("etag"))&&(T.etag[o]=w)),204===e||"HEAD"===h.type?C="nocontent":304===e?C="notmodified":(C=x.state,p=x.data,d=x.error,c=!d)):(d=C,!e&&C||(C="error",e<0&&(e=0))),S.status=e,S.statusText=(t||C)+"",c?m.resolveWith(v,[p,C,S]):m.rejectWith(v,[S,C,d]),S.statusCode(b),b=void 0,f&&g.trigger(c?"ajaxSuccess":"ajaxError",[S,h,c?p:d]),y.fireWith(v,[S,C]),f&&(g.trigger("ajaxComplete",[S,h]),--T.active||T.event.trigger("ajaxStop")))}"object"==typeof e&&(t=e,e=void 0),t=t||{};var r,o,i,s,u,c,l,f,p,d,h=T.ajaxSetup({},t),v=h.context||h,g=h.context&&(v.nodeType||v.jquery)?T(v):T.event,m=T.Deferred(),y=T.Callbacks("once memory"),b=h.statusCode||{},x={},w={},C="canceled",S={readyState:0,getResponseHeader:function(e){var t;if(l){if(!s)for(s={};t=We.exec(i);)s[t[1].toLowerCase()+" "]=(s[t[1].toLowerCase()+" "]||[]).concat(t[2]);t=s[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return l?i:null},setRequestHeader:function(e,t){return null==l&&(e=w[e.toLowerCase()]=w[e.toLowerCase()]||e,x[e]=t),this},overrideMimeType:function(e){return null==l&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(l)S.always(e[S.status]);else for(t in e)b[t]=[b[t],e[t]];return this},abort:function(e){var t=e||C;return r&&r.abort(t),done(0,t),this}};if(m.promise(S),h.url=((e||h.url||Oe.href)+"").replace(Ge,Oe.protocol+"//"),h.type=t.method||t.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(P)||[""],null==h.crossDomain){c=a.createElement("a");try{c.href=h.url,c.href=c.href,h.crossDomain=Je.protocol+"//"+Je.host!=c.protocol+"//"+c.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=T.param(h.data,h.traditional)),inspectPrefiltersOrTransports(Ve,h,t,S),l)return S;f=T.event&&h.global,f&&0==T.active++&&T.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!$e.test(h.type),o=h.url.replace(Re,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(ze,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(Le.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ie,"$1"),d=(Le.test(o)?"&":"?")+"_="+Pe+++d),h.url=o+d),h.ifModified&&(T.lastModified[o]&&S.setRequestHeader("If-Modified-Since",T.lastModified[o]),T.etag[o]&&S.setRequestHeader("If-None-Match",T.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||t.contentType)&&S.setRequestHeader("Content-Type",h.contentType),S.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+Xe+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)S.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(v,S,h)||l))return S.abort();if(C="abort",y.add(h.complete),S.done(h.success),S.fail(h.error),r=inspectPrefiltersOrTransports(Ue,h,t,S)){if(S.readyState=1,f&&g.trigger("ajaxSend",[S,h]),l)return S;h.async&&h.timeout>0&&(u=n.setTimeout(function(){S.abort("timeout")},h.timeout));try{l=!1,r.send(x,done)}catch(e){if(l)throw e;done(-1,e)}}else done(-1,"No Transport");return S},getJSON:function(e,t,n){return T.get(e,t,n,"json")},getScript:function(e,t){return T.get(e,void 0,t,"script")}}),T.each(["get","post"],function(e,t){T[t]=function(e,n,r,o){return b(n)&&(o=o||r,r=n,n=void 0),T.ajax(T.extend({url:e,type:t,dataType:o,data:n,success:r},T.isPlainObject(e)&&e))}}),T._evalUrl=function(e,t){return T.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){T.globalEval(e,t)}})},T.fn.extend({wrapAll:function(e){var t;return this[0]&&(b(e)&&(e=e.call(this[0])),t=T(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return b(e)?this.each(function(t){T(this).wrapInner(e.call(this,t))}):this.each(function(){var t=T(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b(e);return this.each(function(n){T(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){T(this).replaceWith(this.childNodes)}),this}}),T.expr.pseudos.hidden=function(e){return!T.expr.pseudos.visible(e)},T.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},T.ajaxSettings.xhr=function(){try{return new n.XMLHttpRequest}catch(e){}};var Ye={0:200,1223:204},Qe=T.ajaxSettings.xhr();y.cors=!!Qe&&"withCredentials"in Qe,y.ajax=Qe=!!Qe,T.ajaxTransport(function(e){var t,r;if(y.cors||Qe&&!e.crossDomain)return{send:function(o,i){var s,a=e.xhr();if(a.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(s in e.xhrFields)a[s]=e.xhrFields[s];e.mimeType&&a.overrideMimeType&&a.overrideMimeType(e.mimeType),e.crossDomain||o["X-Requested-With"]||(o["X-Requested-With"]="XMLHttpRequest");for(s in o)a.setRequestHeader(s,o[s]);t=function(e){return function(){t&&(t=r=a.onload=a.onerror=a.onabort=a.ontimeout=a.onreadystatechange=null,"abort"===e?a.abort():"error"===e?"number"!=typeof a.status?i(0,"error"):i(a.status,a.statusText):i(Ye[a.status]||a.status,a.statusText,"text"!==(a.responseType||"text")||"string"!=typeof a.responseText?{binary:a.response}:{text:a.responseText},a.getAllResponseHeaders()))}},a.onload=t(),r=a.onerror=a.ontimeout=t("error"),void 0!==a.onabort?a.onabort=r:a.onreadystatechange=function(){4===a.readyState&&n.setTimeout(function(){t&&r()})},t=t("abort");try{a.send(e.hasContent&&e.data||null)}catch(e){if(t)throw e}},abort:function(){t&&t()}}}),T.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),T.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return T.globalEval(e),e}}}),T.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),T.ajaxTransport("script",function(e){if(e.crossDomain||e.scriptAttrs){var t,n;return{send:function(r,o){t=T("