From e4c38302e08e24e4c0abd1f6acb0e33fa5dcb3dd Mon Sep 17 00:00:00 2001 From: Serafeim Papastefanos Date: Tue, 15 Apr 2014 21:55:24 +0300 Subject: [PATCH 001/293] Add fields for scheduled publishing Also add a clean method to Page to check that expiry date is in the future and that go live date is before expiry date. In order to display the correct error message the views/pages.py view has to be changed to display the error message from clean. Finally add the migration for the new fields. --- wagtail/wagtailadmin/views/pages.py | 7 +- .../0003_fields_for_scheduled_publishing.py | 130 ++++++++++++++++++ wagtail/wagtailcore/models.py | 24 +++- 3 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 wagtail/wagtailcore/migrations/0003_fields_for_scheduled_publishing.py diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index 3fb90571517..9e71a612f02 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -7,7 +7,7 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.auth.decorators import permission_required from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger -from django.utils.translation import ugettext as _ +from django.utils.translation import ugettext as _ from django.views.decorators.vary import vary_on_headers from wagtail.wagtailadmin.edit_handlers import TabbedInterface, ObjectList @@ -199,7 +199,10 @@ def clean_slug(slug): return redirect('wagtailadmin_explore', page.get_parent().id) else: - messages.error(request, _("The page could not be created due to errors.")) + if form.errors and form.errors.get('__all__'): + messages.error(request, _("The page could not be created: ") + ', '.join(form.errors['__all__'])) + else: + messages.error(request, _("The page could not be created due to errors.")) edit_handler = edit_handler_class(instance=page, form=form) else: form = form_class(instance=page) diff --git a/wagtail/wagtailcore/migrations/0003_fields_for_scheduled_publishing.py b/wagtail/wagtailcore/migrations/0003_fields_for_scheduled_publishing.py new file mode 100644 index 00000000000..5e682aa596b --- /dev/null +++ b/wagtail/wagtailcore/migrations/0003_fields_for_scheduled_publishing.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'PageRevision.approved_go_live_datetime' + db.add_column(u'wagtailcore_pagerevision', 'approved_go_live_datetime', + self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), + keep_default=False) + + # Adding field 'Page.go_live_datetime' + db.add_column(u'wagtailcore_page', 'go_live_datetime', + self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), + keep_default=False) + + # Adding field 'Page.expiry_datetime' + db.add_column(u'wagtailcore_page', 'expiry_datetime', + self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), + keep_default=False) + + # Adding field 'Page.expired' + db.add_column(u'wagtailcore_page', 'expired', + self.gf('django.db.models.fields.BooleanField')(default=False), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'PageRevision.approved_go_live_datetime' + db.delete_column(u'wagtailcore_pagerevision', 'approved_go_live_datetime') + + # Deleting field 'Page.go_live_datetime' + db.delete_column(u'wagtailcore_page', 'go_live_datetime') + + # Deleting field 'Page.expiry_datetime' + db.delete_column(u'wagtailcore_page', 'expiry_datetime') + + # Deleting field 'Page.expired' + db.delete_column(u'wagtailcore_page', 'expired') + + + models = { + u'auth.group': { + 'Meta': {'object_name': 'Group'}, + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + u'auth.permission': { + 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + u'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + u'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + u'wagtailcore.grouppagepermission': { + 'Meta': {'object_name': 'GroupPagePermission'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'page_permissions'", 'to': u"orm['auth.Group']"}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_permissions'", 'to': u"orm['wagtailcore.Page']"}), + 'permission_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}) + }, + u'wagtailcore.page': { + 'Meta': {'object_name': 'Page'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pages'", 'to': u"orm['contenttypes.ContentType']"}), + 'depth': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'expiry_datetime': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'go_live_datetime': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'has_unpublished_changes': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'live': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'numchild': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'owned_pages'", 'null': 'True', 'to': u"orm['auth.User']"}), + 'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'search_description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'seo_title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'show_in_menus': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'url_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}) + }, + u'wagtailcore.pagerevision': { + 'Meta': {'object_name': 'PageRevision'}, + 'approved_go_live_datetime': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'content_json': ('django.db.models.fields.TextField', [], {}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': u"orm['wagtailcore.Page']"}), + 'submitted_for_moderation': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}) + }, + u'wagtailcore.site': { + 'Meta': {'object_name': 'Site'}, + 'hostname': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_default_site': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'port': ('django.db.models.fields.IntegerField', [], {'default': '80'}), + 'root_page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sites_rooted_here'", 'to': u"orm['wagtailcore.Page']"}) + } + } + + complete_apps = ['wagtailcore'] \ No newline at end of file diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index d322ab69b5b..96e670ef928 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -7,10 +7,13 @@ from django.db.models import get_model, Q from django.http import Http404 from django.core.cache import cache +from django.core.exceptions import ValidationError from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import Group from django.conf import settings from django.template.response import TemplateResponse +from django.utils import timezone +from django.utils.translation import ugettext from django.utils.translation import ugettext_lazy as _ from wagtail.wagtailcore.util import camelcase_to_underscore @@ -234,6 +237,10 @@ class Page(MP_Node, ClusterableModel, Indexed): show_in_menus = models.BooleanField(default=False, help_text=_("Whether a link to this page will appear in automatically generated menus")) search_description = models.TextField(blank=True) + go_live_datetime = models.DateTimeField(verbose_name=_("Go live date/time"), blank=True, null=True) + expiry_datetime = models.DateTimeField(verbose_name=_("Expiry date/time"), blank=True, null=True) + expired = models.BooleanField(default=False, editable=False) + indexed_fields = { 'title': { 'type': 'string', @@ -320,7 +327,7 @@ def _update_descendant_url_paths(self, old_url_path, new_url_path): SET url_path = %s || substring(url_path from %s) WHERE path LIKE %s AND id <> %s """ - cursor.execute(update_statement, + cursor.execute(update_statement, [new_url_path, len(old_url_path) + 1, self.path + '%', self.id]) @property @@ -399,8 +406,8 @@ def get_template(self, request): def serve(self, request): return TemplateResponse( - request, - self.get_template(request), + request, + self.get_template(request), self.get_context(request) ) @@ -448,6 +455,16 @@ def relative_url(self, current_site): if self.url_path.startswith(root_path): return ('' if current_site.id == id else root_url) + self.url_path[len(root_path) - 1:] + def clean(self): + super(Page, self).clean() + + if self.go_live_datetime and self.expiry_datetime: + if self.go_live_datetime > self.expiry_datetime: + raise ValidationError(ugettext('Go live date/time should be before expiry datetime.')) + + if self.expiry_datetime and self.expiry_datetime < timezone.now(): + raise ValidationError(ugettext('Expiry date/time should be in the future')) + @classmethod def search(cls, query_string, show_unpublished=False, search_title_only=False, extra_filters={}, prefetch_related=[], path=None): # Filters @@ -642,6 +659,7 @@ class PageRevision(models.Model): created_at = models.DateTimeField(auto_now_add=True) user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True) content_json = models.TextField() + approved_go_live_datetime = models.DateTimeField(null=True, blank=True) objects = models.Manager() submitted_revisions = SubmittedRevisionsManager() From a40c71687de01c6ccf2d8c983a14dc41eec82bea Mon Sep 17 00:00:00 2001 From: Serafeim Papastefanos Date: Wed, 16 Apr 2014 10:27:07 +0300 Subject: [PATCH 002/293] Show clean model errors on edit also --- wagtail/wagtailadmin/views/pages.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index 9e71a612f02..703d9f8ddb4 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -279,7 +279,11 @@ def clean_slug(slug): return redirect('wagtailadmin_explore', page.get_parent().id) else: - messages.error(request, _("The page could not be saved due to validation errors")) + if form.errors and form.errors.get('__all__'): + messages.error(request, _("The page could not be saved: ") + ', '.join(form.errors['__all__'])) + else: + messages.error(request, _("The page could not be saved due to validation errors")) + edit_handler = edit_handler_class(instance=page, form=form) errors_debug = ( repr(edit_handler.form.errors) From 1ebe234a7eebe761fdbf7bbbb1bc32480e840a85 Mon Sep 17 00:00:00 2001 From: Serafeim Papastefanos Date: Wed, 16 Apr 2014 01:05:15 +0300 Subject: [PATCH 003/293] Add go_live_datetime handling on views/models The logic for publishing a page exists in the create and edit views of wagtailadmin.views.pages and in the publish methodd of hte PageRevision model. When a page is created and published (create view), if it has a go_live in the future then it will not be live but the revision that will be created will have the approved_go_live set to the corresponding datetime. If the page is just saved or submitted for moderation the normal flow will be followed. When a page is edited and published (edit view): * The approved_go_live_datetime will be cleared for all older revisions of that page. * If the edit has a go_live in the future then the new revision that will be crated will have the approved_go_live set to that datetime. Also the live attribute of the page will be set to False. If the page is edited and not published the normal flow will be followed. When a submitted for moderation page is published (publish method): * If it has a go_live in the future then the live attribute will be set to False, the approved_go_live_datetime of the revision will be set to the go_live_datetime of the page and the approved_go_live_datetime of all other revisions will be cleared. * If it does not have a go_live in the future then the page will be live and the approved_go_live_dattime of all other revisions will be cleard Finally, if a page is unpublished then then approved_go_live_datetime of all revisions of that page will be cleared. --- wagtail/wagtailadmin/views/pages.py | 44 +++++++++++++++++++++++++---- wagtail/wagtailcore/models.py | 32 ++++++++++++++++++--- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index 703d9f8ddb4..8193bdfc444 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -7,6 +7,7 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.auth.decorators import permission_required from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger +from django.utils import timezone from django.utils.translation import ugettext as _ from django.views.decorators.vary import vary_on_headers @@ -173,16 +174,31 @@ def clean_slug(slug): is_publishing = bool(request.POST.get('action-publish')) and parent_page_perms.can_publish_subpage() is_submitting = bool(request.POST.get('action-submit')) + go_live_datetime = form.cleaned_data.get('go_live_datetime') + future_go_live = go_live_datetime and go_live_datetime > timezone.now() + approved_go_live_datetime = None - if is_publishing: + if is_publishing and not future_go_live: page.live = True page.has_unpublished_changes = False + elif is_publishing and future_go_live: + page.live = False + # Set approved_go_live_datetime only if is publishing + # and the future_go_live is actually in future + approved_go_live_datetime = go_live_datetime + page.has_unpublished_changes = False else: page.live = False page.has_unpublished_changes = True parent_page.add_child(page) # assign tree parameters - will cause page to be saved - page.save_revision(user=request.user, submitted_for_moderation=is_submitting) + + # Pass approved_go_live_datetime to save_revision + page.save_revision( + user=request.user, + submitted_for_moderation=is_submitting, + approved_go_live_datetime = approved_go_live_datetime + ) if is_publishing: messages.success(request, _("Page '{0}' published.").format(page.title)) @@ -245,12 +261,24 @@ def clean_slug(slug): if form.is_valid(): is_publishing = bool(request.POST.get('action-publish')) and page_perms.can_publish() is_submitting = bool(request.POST.get('action-submit')) + go_live_datetime = form.cleaned_data.get('go_live_datetime') + future_go_live = go_live_datetime and go_live_datetime > timezone.now() + approved_go_live_datetime = None if is_publishing: - page.live = True page.has_unpublished_changes = False + if future_go_live: + page.live = False + # Set approved_go_live_datetime only if publishing + approved_go_live_datetime = go_live_datetime + else: + page.live = True form.save() - page.revisions.update(submitted_for_moderation=False) + # Clear approved_go_live_datetime for older revisions + page.revisions.update( + submitted_for_moderation=False, + approved_go_live_datetime=None, + ) else: # not publishing the page if page.live: @@ -262,7 +290,11 @@ def clean_slug(slug): page.has_unpublished_changes = True form.save() - page.save_revision(user=request.user, submitted_for_moderation=is_submitting) + page.save_revision( + user=request.user, + submitted_for_moderation=is_submitting, + approved_go_live_datetime = approved_go_live_datetime + ) if is_publishing: messages.success(request, _("Page '{0}' published.").format(page.title)) @@ -443,6 +475,8 @@ def unpublish(request, page_id): parent_id = page.get_parent().id page.live = False page.save() + # Since page is unpublished clear the approved_go_live_datetime of all revisions + page.revisions.update(approved_go_live_datetime=None) messages.success(request, _("Page '{0}' unpublished.").format(page.title)) return redirect('wagtailadmin_explore', parent_id) diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index 96e670ef928..1ecdd1eb000 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -373,8 +373,13 @@ def route(self, request, path_components): else: raise Http404 - def save_revision(self, user=None, submitted_for_moderation=False): - self.revisions.create(content_json=self.to_json(), user=user, submitted_for_moderation=submitted_for_moderation) + def save_revision(self, user=None, submitted_for_moderation=False, approved_go_live_datetime=None): + self.revisions.create( + content_json=self.to_json(), + user=user, + submitted_for_moderation=submitted_for_moderation, + approved_go_live_datetime=approved_go_live_datetime, + ) def get_latest_revision(self): try: @@ -539,13 +544,20 @@ def get_verbose_name(cls): @property def status_string(self): if not self.live: - return "draft" + if self.approved_schedule: + return "scheduled" + else: + return "draft" else: if self.has_unpublished_changes: return "live + draft" else: return "live" + @property + def approved_schedule(self): + return self.revisions.exclude(approved_go_live_datetime__isnull=True).exists() + def has_unpublished_subtree(self): """ An awkwardly-defined flag used in determining whether unprivileged editors have @@ -693,11 +705,23 @@ def as_page_object(self): def publish(self): page = self.as_page_object() - page.live = True + if page.go_live_datetime and page.go_live_datetime > timezone.now(): + # if we have a go_live in the future don't make the page live + page.live = False + # Instead set the approved_go_live_datetime of this revision + self.approved_go_live_datetime = page.go_live_datetime + self.save() + # And clear the the approved_go_live_datetime of any other revisions + page.revisions.exclude(id=self.id).update(approved_go_live_datetime=None) + else: + page.live = True + # If page goes live clear the approved_go_live_datetime of all revisions + page.revisions.update(approved_go_live_datetime=None) page.save() self.submitted_for_moderation = False page.revisions.update(submitted_for_moderation=False) + PAGE_PERMISSION_TYPE_CHOICES = [ ('add', 'Add'), ('edit', 'Edit'), From 2ebf9ba931895f32d7657847fbb7f0bf4a728219 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 17 Apr 2014 17:54:54 +0100 Subject: [PATCH 004/293] first commit of new styleguide --- .../wagtailadmin/scss/layouts/styleguide.scss | 77 +++++++ .../wagtailadmin/styleguide/base.html | 213 ++++++++++++++++++ wagtail/wagtailadmin/urls.py | 2 + wagtail/wagtailadmin/views/styleguide.py | 9 + 4 files changed, 301 insertions(+) create mode 100644 wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss create mode 100644 wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html create mode 100644 wagtail/wagtailadmin/views/styleguide.py diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss new file mode 100644 index 00000000000..8e0894baad6 --- /dev/null +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss @@ -0,0 +1,77 @@ +@import "../variables.scss"; +@import "../mixins.scss"; +@import "../grid.scss"; + +section{ + border-top:1px solid $color-grey-3; + padding:0 0 2em 0; + + > h2:first-child{ + margin:0; + font-size:1em; + background:$color-grey-4; + padding:1em; + margin-bottom:1em; + } +} + +#palette{ + @include clearfix(); + + ul{ + @include clearfix(); + @include unlist(); + } + + li{ + float:left; + width:100px; + height:100px; + padding:10px; + color:black; + } + + .color-teal{ + background-color:$color-teal; + } + .color-teal-darker{ + background-color:$color-teal-darker; + } + .color-teal-dark{ + background-color:$color-teal-dark; + } + .color-red{ + background-color:$color-red; + } + .color-orange{ + background-color:$color-orange; + } + .color-green{ + background-color:$color-green; + } + .color-grey-1{ + background-color:$color-grey-1; + } + .color-grey-1-1{ + background-color:$color-grey-1-1; + } + .color-grey-2{ + background-color:$color-grey-2; + } + .color-grey-3{ + background-color:$color-grey-3; + } + .color-grey-4{ + background-color:$color-grey-4; + } + .color-grey-5{ + background-color:$color-grey-5; + } +} + + +#icons{ + ul{ + @include unlist(); + } +} \ No newline at end of file diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html b/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html new file mode 100644 index 00000000000..9f9eea9228c --- /dev/null +++ b/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html @@ -0,0 +1,213 @@ +{% extends "wagtailadmin/base.html" %} +{% load wagtailadmin_tags %} +{% load compress i18n %} + +{% block extra_css %} + {% compress css %} + + {% endcompress %} +{% endblock %} + +{% block titletag %}{% trans 'Styleguide' %}{% endblock %} +{% block bodyclass %}styleguide{% endblock %} + +{% block content %} + {% trans "Styleguide" as title_trans %} + {% include "wagtailadmin/shared/header.html" with title=title_trans %} + +
+

Styleguide

+ + +
+

Colour palette

+ +
    +
  • color-teal
  • +
  • color-teal-darker
  • +
  • color-teal-dark
  • +
  • color-red
  • +
  • color-orange
  • +
  • color-green
  • +
+
    +
  • color-grey-1
  • +
  • color-grey-1-1
  • +
  • color-grey-2
  • +
  • color-grey-3
  • +
  • color-grey-4
  • +
  • color-grey-5
  • +
+
+ +
+

Typography

+

This is an h1

+

This is an h2

+

This is an h3

+

This is an h4

+
This is an h5
+

This is a paragraph

+ +
    +
  • These are
  • +
  • items in an
  • +
  • unordered list
  • +
+ +
    +
  1. These are
  2. +
  3. items in an
  4. +
  5. ordered list
  6. +
+ +
+ +
+

Listings

+
+ +
+

Buttons

+ +
button
+ +
button-secondary
+ +
yes
+ +
no / serious
+ +
bicolor with icon
+ +
button-small
+ +
bicolo button-small
+ +
mixed
+ +
+ + + + + +
+

Messages

+
+ +
+

Forms

+
+ +
+

Page editor

+
+ +
+

Tabs

+
+ + + +
+

Misc formatters

+

Avatar icons

+

Status tags

+
+ +
+

Icons

+ +
    +
  • wagtail
  • +
  • wagtail-inverse
  • +
  • cogs
  • +
  • doc-empty-inverse
  • +
  • doc-empty
  • +
  • edit
  • +
  • arrow-up
  • +
  • arrow-down
  • + +
  • cross
  • +
  • folder-open-1
  • +
  • folder-inverse
  • +
  • mail
  • +
  • arrows-up-down
  • +
  • locked
  • +
  • unlocked
  • +
  • arrow-right
  • +
  • doc-full / file-text-alt
  • +
  • image / picture
  • +
  • doc-full-inverse
  • +
  • folder
  • +
  • plus
  • +
  • tag
  • +
  • folder-open-inverse
  • +
  • cog
  • +
  • tick
  • +
  • user
  • +
  • arrow-left
  • +
  • tick-inverse
  • +
  • plus-inverse
  • +
  • snippet
  • +
  • bold
  • +
  • italic
  • +
  • undo
  • +
  • repeat
  • +
  • list-ol
  • +
  • list-ul
  • + +
  • radio-full
  • +
  • radio-empty
  • +
  • arrow-up-big
  • +
  • arrow-down-big
  • +
  • group
  • +
  • media
  • +
  • horizontalrule
  • +
  • password
  • +
  • download
  • +
  • order
  • +
  • grip
  • +
  • home
  • +
  • order-down
  • +
  • order-up
  • +
  • bin
  • +
  • spinner
  • +
  • pick
  • +
  • redirect
  • +
  • view
  • +
  • collapse-up
  • +
  • collapse-down
  • +
  • help
  • +
  • warning
  • +
  • success
  • +
+ +
+ + +
+{% endblock %} \ No newline at end of file diff --git a/wagtail/wagtailadmin/urls.py b/wagtail/wagtailadmin/urls.py index 3b1a9853572..1241004a2d8 100644 --- a/wagtail/wagtailadmin/urls.py +++ b/wagtail/wagtailadmin/urls.py @@ -82,4 +82,6 @@ url(r'^userbar/(\d+)/$', 'userbar.for_frontend', name='wagtailadmin_userbar_frontend'), url(r'^userbar/moderation/(\d+)/$', 'userbar.for_moderation', name='wagtailadmin_userbar_moderation'), + + url(r'^styleguide/$', 'styleguide.index', name='wagtailadmin_styleguide'), ) diff --git a/wagtail/wagtailadmin/views/styleguide.py b/wagtail/wagtailadmin/views/styleguide.py new file mode 100644 index 00000000000..33c87034c9e --- /dev/null +++ b/wagtail/wagtailadmin/views/styleguide.py @@ -0,0 +1,9 @@ +from django.shortcuts import render + +from wagtail.wagtailadmin.userbar import EditPageItem, AddPageItem, ApproveModerationEditPageItem, RejectModerationEditPageItem +from wagtail.wagtailadmin import hooks +from wagtail.wagtailcore.models import Page, PageRevision + +def index(request): + # Render the edit bird + return render(request, 'wagtailadmin/styleguide/base.html', {}) From 89f2d76bfdcd49cb9c132342b83e29fc29a8ac44 Mon Sep 17 00:00:00 2001 From: Serafeim Papastefanos Date: Mon, 21 Apr 2014 18:03:57 +0300 Subject: [PATCH 005/293] Set expired = False when publishing pages both ... in views and models and refactor code a bit. --- wagtail/wagtailadmin/views/pages.py | 18 ++++++++++-------- wagtail/wagtailcore/models.py | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index 8193bdfc444..7b181b5fde1 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -178,15 +178,16 @@ def clean_slug(slug): future_go_live = go_live_datetime and go_live_datetime > timezone.now() approved_go_live_datetime = None - if is_publishing and not future_go_live: - page.live = True - page.has_unpublished_changes = False - elif is_publishing and future_go_live: - page.live = False - # Set approved_go_live_datetime only if is publishing - # and the future_go_live is actually in future - approved_go_live_datetime = go_live_datetime + if is_publishing: page.has_unpublished_changes = False + page.expired = False + if future_go_live: + page.live = False + # Set approved_go_live_datetime only if is publishing + # and the future_go_live is actually in future + approved_go_live_datetime = go_live_datetime + else: + page.live = True else: page.live = False page.has_unpublished_changes = True @@ -267,6 +268,7 @@ def clean_slug(slug): if is_publishing: page.has_unpublished_changes = False + page.expired = False if future_go_live: page.live = False # Set approved_go_live_datetime only if publishing diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index 1ecdd1eb000..eda1a91ec57 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -717,6 +717,7 @@ def publish(self): page.live = True # If page goes live clear the approved_go_live_datetime of all revisions page.revisions.update(approved_go_live_datetime=None) + page.expired = False # When a page is published it can't be expired page.save() self.submitted_for_moderation = False page.revisions.update(submitted_for_moderation=False) From 792b37d9564e3ae32f0acccda9427740a6b4541f Mon Sep 17 00:00:00 2001 From: Serafeim Papastefanos Date: Mon, 21 Apr 2014 18:08:47 +0300 Subject: [PATCH 006/293] Add "expired" status to pages --- wagtail/wagtailcore/models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index eda1a91ec57..5348acf8412 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -544,7 +544,9 @@ def get_verbose_name(cls): @property def status_string(self): if not self.live: - if self.approved_schedule: + if self.expired: + return "expired" + elif self.approved_schedule: return "scheduled" else: return "draft" From 6839a7474ab32873bfffb2b48237d500538ca7c7 Mon Sep 17 00:00:00 2001 From: Serafeim Papastefanos Date: Mon, 21 Apr 2014 21:48:23 +0300 Subject: [PATCH 007/293] Add management command for scheduled pages The publish_scheduled_pages management command does three actions: * Gets live pages which have an expiry_datetime that has passed and set expired = True and live = False * Gets all revisions on the moderation queue which have an expiry_datetime that has passed and remove them from the moderation queue * Gets all revisions that have an approved_go_live_datetime that has passed. For each one of them the publish() method of the revision is called which will perform the required actions for making live this version of the page. Finally, a dryrun parameter has been added to the management command. If this parameter is used then the pages that pass the tests for each of the above lists will be printed. --- .../commands/publish_scheduled_pages.py | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 wagtail/wagtailcore/management/commands/publish_scheduled_pages.py diff --git a/wagtail/wagtailcore/management/commands/publish_scheduled_pages.py b/wagtail/wagtailcore/management/commands/publish_scheduled_pages.py new file mode 100644 index 00000000000..0abf3c744e5 --- /dev/null +++ b/wagtail/wagtailcore/management/commands/publish_scheduled_pages.py @@ -0,0 +1,109 @@ +import datetime +import json +from optparse import make_option + +from django.core.management.base import BaseCommand +from django.utils import dateparse, timezone +from wagtail.wagtailcore.models import Page, PageRevision + + +def revision_date_expired(r): + expiry_str = json.loads(r.content_json).get('expiry_datetime') + if not expiry_str: + return False + expiry_datetime = dateparse.parse_datetime(expiry_str) + if expiry_datetime < timezone.now(): + return True + else: + return False + + +class Command(BaseCommand): + option_list = BaseCommand.option_list + ( + make_option( + '--dryrun', + action='store_true', + dest='dryrun', + default=False, + help='Dry run -- don\'t change anything.'), + ) + + def handle(self, *args, **options): + dryrun = False + if options['dryrun']: + print "Will do a dry run." + dryrun = True + + # 1. get all expired pages with live = True + expired_pages = Page.objects.filter( + live=True, + expiry_datetime__lt=timezone.now() + ) + if dryrun: + if expired_pages: + print "Expired pages to be deactivated:" + print "Expiry datetime\t\tSlug\t\tName" + print "---------------\t\t----\t\t----" + for ep in expired_pages: + print "{0}\t{1}\t{2}".format( + ep.expiry_datetime.strftime("%Y-%m-%d %H:%M"), + ep.slug, + ep.title + ) + else: + print "No expired pages to be deactivated found." + else: + expired_pages.update(expired=True, live=False) + + # 2. get all page revisions for moderation that have been expired + expired_revs = [ + r for r in PageRevision.objects.filter( + submitted_for_moderation=True + ) if revision_date_expired(r) + ] + if dryrun: + print "---------------------------------" + if expired_revs: + print "Expired revisions to be dropped from moderation queue:" + print "Expiry datetime\t\tSlug\t\tName" + print "---------------\t\t----\t\t----" + for er in expired_revs: + rev_data = json.loads(er.content_json) + print "{0}\t{1}\t{2}".format( + dateparse.parse_datetime( + rev_data.get('expiry_datetime') + ).strftime("%Y-%m-%d %H:%M"), + rev_data.get('slug'), + rev_data.get('title') + ) + else: + print "No expired revision to be dropped from moderation." + else: + for er in expired_revs: + er.submitted_for_moderation = False + er.save() + + # 3. get all revisions that need to be published + revs_for_publishing = PageRevision.objects.filter( + approved_go_live_datetime__lt=timezone.now() + ) + if dryrun: + print "---------------------------------" + if revs_for_publishing: + print "Revisions to be published:" + print "Go live datetime\t\tSlug\t\tName" + print "---------------\t\t\t----\t\t----" + for rp in revs_for_publishing: + rev_data = json.loads(rp.content_json) + print "{0}\t\t{1}\t{2}".format( + rp.approved_go_live_datetime.strftime("%Y-%m-%d %H:%M"), + rev_data.get('slug'), + rev_data.get('title') + ) + else: + print "No pages to go live." + else: + for rp in revs_for_publishing: + # just run publish for the revision -- since the approved go + # live datetime is before now it will make the page live + rp.publish() From 686a9beaa9099ac8f4cca20004f35321e6bdd09e Mon Sep 17 00:00:00 2001 From: Serafeim Papastefanos Date: Tue, 22 Apr 2014 20:12:20 +0300 Subject: [PATCH 008/293] Add tests for scheduled publishing This does not actually test the management command for scheduled pages. --- wagtail/wagtailadmin/tests.py | 140 ++++++++++++++++++++++++++++++++-- 1 file changed, 134 insertions(+), 6 deletions(-) diff --git a/wagtail/wagtailadmin/tests.py b/wagtail/wagtailadmin/tests.py index 84b00b3355d..3df92ec2247 100644 --- a/wagtail/wagtailadmin/tests.py +++ b/wagtail/wagtailadmin/tests.py @@ -1,8 +1,10 @@ +from datetime import datetime, timedelta +from django.utils import timezone from django.test import TestCase import unittest from wagtail.tests.models import SimplePage, EventPage from wagtail.tests.utils import login -from wagtail.wagtailcore.models import Page +from wagtail.wagtailcore.models import Page, PageRevision from django.core.urlresolvers import reverse @@ -49,7 +51,7 @@ def test_select_type(self): response = self.client.get(reverse('wagtailadmin_pages_select_type')) self.assertEqual(response.status_code, 200) - @unittest.expectedFailure # For some reason, this returns a 302... + @unittest.expectedFailure # For some reason, this returns a 302... def test_select_location_testpage(self): response = self.client.get(reverse('wagtailadmin_pages_select_location', args=('tests', 'eventpage'))) self.assertEqual(response.status_code, 200) @@ -100,6 +102,57 @@ def test_create_simplepage_post(self): self.assertIsInstance(page, SimplePage) self.assertFalse(page.live) + def test_create_simplepage_scheduled(self): + go_live_datetime = timezone.now() + timedelta(days=1) + expiry_datetime = timezone.now() + timedelta(days=2) + post_data = { + 'title': "New page!", + 'content': "Some content", + 'slug': 'hello-world', + 'go_live_datetime': str(go_live_datetime), + 'expiry_datetime': str(expiry_datetime), + } + response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data) + + # Should be redirected to explorer page + self.assertEqual(response.status_code, 302) + + # Find the page and check the scheduled times + page = Page.objects.get(path__startswith=self.root_page.path, slug='hello-world').specific + self.assertEquals(page.go_live_datetime.date(), go_live_datetime.date()) + self.assertEquals(page.expiry_datetime.date(), expiry_datetime.date()) + self.assertEquals(page.expired, False) + self.assertTrue(page.status_string, "draft") + + # No revisions with approved_go_live_datetime + self.assertFalse(PageRevision.objects.filter(page=page).exclude(approved_go_live_datetime__isnull=True).exists()) + + def test_create_simplepage_scheduled_errored(self): + post_data = { + 'title': "New page!", + 'content': "Some content", + 'slug': 'hello-world', + 'go_live_datetime': str(timezone.now() + timedelta(days=2)), + 'expiry_datetime': str(timezone.now() + timedelta(days=1)), + } + response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data) + + # Should be redirected to explorer page + self.assertEqual(response.status_code, 200) + self.assertTrue(response.context['edit_handler'].form.errors) + + post_data = { + 'title': "New page!", + 'content': "Some content", + 'slug': 'hello-world', + 'expiry_datetime': str(timezone.now() + timedelta(days=-1)), + } + response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data) + + # Should be redirected to explorer page + self.assertEqual(response.status_code, 200) + self.assertTrue(response.context['edit_handler'].form.errors) + def test_create_simplepage_post_publish(self): post_data = { 'title': "New page!", @@ -118,6 +171,34 @@ def test_create_simplepage_post_publish(self): self.assertIsInstance(page, SimplePage) self.assertTrue(page.live) + def test_create_simplepage_post_publish_scheduled(self): + go_live_datetime = timezone.now() + timedelta(days=1) + expiry_datetime = timezone.now() + timedelta(days=2) + post_data = { + 'title': "New page!", + 'content': "Some content", + 'slug': 'hello-world', + 'action-publish': "Publish", + 'go_live_datetime': str(go_live_datetime), + 'expiry_datetime': str(expiry_datetime), + } + response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data) + + # Should be redirected to explorer page + self.assertEqual(response.status_code, 302) + + # Find the page and check it + page = Page.objects.get(path__startswith=self.root_page.path, slug='hello-world').specific + self.assertEquals(page.go_live_datetime.date(), go_live_datetime.date()) + self.assertEquals(page.expiry_datetime.date(), expiry_datetime.date()) + self.assertEquals(page.expired, False) + + # A revision with approved_go_live_datetime should exist now + self.assertTrue(PageRevision.objects.filter(page=page).exclude(approved_go_live_datetime__isnull=True).exists()) + # But Page won't be live + self.assertFalse(page.live) + self.assertTrue(page.status_string, "scheduled") + def test_create_simplepage_post_existingslug(self): # This tests the existing slug checking on page save @@ -143,7 +224,7 @@ def test_create_nonexistantparent(self): response = self.client.get(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', 100000))) self.assertEqual(response.status_code, 404) - @unittest.expectedFailure # FIXME: Crashes! + @unittest.expectedFailure # FIXME: Crashes! def test_create_nonpagetype(self): response = self.client.get(reverse('wagtailadmin_pages_create', args=('wagtailimages', 'image', self.root_page.id))) self.assertEqual(response.status_code, 404) @@ -184,7 +265,7 @@ def test_edit_post(self): 'slug': 'hello-world', } response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data) - + # Should be redirected to explorer page self.assertEqual(response.status_code, 302) @@ -192,6 +273,31 @@ def test_edit_post(self): child_page_new = SimplePage.objects.get(id=self.child_page.id) self.assertTrue(child_page_new.has_unpublished_changes) + def test_edit_post_scheduled(self): + go_live_datetime = timezone.now() + timedelta(days=1) + expiry_datetime = timezone.now() + timedelta(days=2) + post_data = { + 'title': "I've been edited!", + 'content': "Some content", + 'slug': 'hello-world', + 'go_live_datetime': str(go_live_datetime), + 'expiry_datetime': str(expiry_datetime), + } + response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data) + + # Should be redirected to explorer page + self.assertEqual(response.status_code, 302) + + child_page_new = SimplePage.objects.get(id=self.child_page.id) + + # The page will still be live + self.assertTrue(child_page_new.live) + # A revision with approved_go_live_datetime should not exist + self.assertFalse(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_datetime__isnull=True).exists()) + # But a revision with go_live_datetime and expiry_datetime in their content json *should* exist + self.assertTrue(PageRevision.objects.filter(page=child_page_new, content_json__contains=str(go_live_datetime.date())).exists()) + self.assertTrue(PageRevision.objects.filter(page=child_page_new, content_json__contains=str(expiry_datetime.date())).exists()) + def test_edit_post_publish(self): # Tests publish from edit page post_data = { @@ -201,7 +307,7 @@ def test_edit_post_publish(self): 'action-publish': "Publish", } response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data) - + # Should be redirected to explorer page self.assertEqual(response.status_code, 302) @@ -212,6 +318,28 @@ def test_edit_post_publish(self): # The page shouldn't have "has_unpublished_changes" flag set self.assertFalse(child_page_new.has_unpublished_changes) + def test_edit_post_publish_scheduled(self): + go_live_datetime = timezone.now() + timedelta(days=1) + expiry_datetime = timezone.now() + timedelta(days=2) + post_data = { + 'title': "I've been edited!", + 'content': "Some content", + 'slug': 'hello-world', + 'action-publish': "Publish", + 'go_live_datetime': str(go_live_datetime), + 'expiry_datetime': str(expiry_datetime), + } + response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data) + + # Should be redirected to explorer page + self.assertEqual(response.status_code, 302) + + child_page_new = SimplePage.objects.get(id=self.child_page.id) + # The page should not be live anymore + self.assertFalse(child_page_new.live) + # Instead a revision with approved_go_live_datetime should not exist + self.assertTrue(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_datetime__isnull=True).exists()) + class TestPageDelete(TestCase): def setUp(self): @@ -232,7 +360,7 @@ def test_delete(self): self.assertEqual(response.status_code, 200) def test_delete_post(self): - post_data = {'hello': 'world'} # For some reason, this test doesn't work without a bit of POST data + post_data = {'hello': 'world'} # For some reason, this test doesn't work without a bit of POST data response = self.client.post(reverse('wagtailadmin_pages_delete', args=(self.child_page.id, )), post_data) # Should be redirected to explorer page From 65f093061dc53abf24f9bb30b0be1d6160a4c0f6 Mon Sep 17 00:00:00 2001 From: Serafeim Papastefanos Date: Wed, 23 Apr 2014 11:56:13 +0300 Subject: [PATCH 009/293] Use the plain DateTimeInput widget for ... go_live_datetime and expiry_datetime. This should probably be improved in order to use a javascript datetime picker. --- wagtail/wagtailadmin/edit_handlers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/edit_handlers.py b/wagtail/wagtailadmin/edit_handlers.py index 245f7ad60d1..370f2f5bbdf 100644 --- a/wagtail/wagtailadmin/edit_handlers.py +++ b/wagtail/wagtailadmin/edit_handlers.py @@ -133,15 +133,18 @@ def to_python(self, time_string): else: raise ValidationError(_("Please type a valid time") ) - +# For some reason we need to explicitly override the DateTimeField and set +# it to use the DateTimeInput or else it will use the LocalizedDateInput/FriendlyDateInput if hasattr(settings, 'USE_L10N') and settings.USE_L10N==True: FORM_FIELD_OVERRIDES = { models.DateField: {'widget': LocalizedDateInput}, + models.DateTimeField: {'widget': forms.DateTimeInput}, models.TimeField: {'widget': LocalizedTimeInput, 'form_class': LocalizedTimeField}, } else: # Fall back to friendly date/time FORM_FIELD_OVERRIDES = { models.DateField: {'widget': FriendlyDateInput}, + models.DateTimeField: {'widget': forms.DateTimeInput}, models.TimeField: {'widget': FriendlyTimeInput, 'form_class': FriendlyTimeField}, } From f9f07f4a83eee89fd740393b364b5744d62e9562 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Wed, 30 Apr 2014 11:37:38 +0100 Subject: [PATCH 010/293] altered buttons --- .../wagtailadmin/templates/wagtailadmin/styleguide/base.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html b/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html index 9f9eea9228c..75f5bcc176e 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html @@ -100,7 +100,9 @@

Buttons

bicolo button-small
-
mixed
+
mixed 1
+ +
mixed 2
From 0f3b74817f7c1fa741c2e5fad18de51f12c323d9 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 8 May 2014 14:26:32 +0100 Subject: [PATCH 011/293] updates to styleguide --- .../scss/components/dropdowns.scss | 53 ++--- .../scss/components/formatters.scss | 4 + .../wagtailadmin/scss/components/listing.scss | 2 + .../wagtailadmin/scss/layouts/styleguide.scss | 13 +- .../wagtailadmin/styleguide/base.html | 186 +++++++++++++++++- wagtail/wagtailadmin/urls.py | 4 +- wagtail/wagtailadmin/views/styleguide.py | 44 ++++- 7 files changed, 269 insertions(+), 37 deletions(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/dropdowns.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/dropdowns.scss index ee618f3771e..1428f0fd9b6 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/dropdowns.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/dropdowns.scss @@ -3,7 +3,18 @@ @include clearfix(); .dropdown-toggle{ + color:white; + text-transform:uppercase; + background-color:$color-teal; + line-height:3em; + padding-left:1em; + padding-right:1em; cursor:pointer; + + &:before, + &:after{ + margin:0; + } } input[type=button], input[type=submit], button, .button{ @@ -27,10 +38,9 @@ li{ float:none; - border-top:1px solid rgba(255,255,255,0.2); - } - li:first-child{ - border-top:0; + border-color: rgba(255,255,255,0.2); + border-style: solid; + border-width:1px 0 0 0; } a{ @@ -101,6 +111,10 @@ @include box-shadow(0px -3px 3px 0 rgba(0,0,0,0.2)); top:auto; bottom:100%; + + li{ + border-width:0 0 1px 0; + } } @@ -134,10 +148,22 @@ } /* Styles for dropdowns which are also buttons e.g page editor */ + &.dropdown-button{ .dropdown-toggle{ @include border-radius(0 3px 3px 0); } + &.open{ + > input[type=button], > input[type=submit], > button, > .button{ + @include border-radius(3px 3px 0px 0px); + } + .dropdown-toggle{ + @include border-radius(0 3px 0 0); + } + } + } + + &.dropup.dropdown-button{ &.open{ > input[type=button], > input[type=submit], > button, > .button{ @include border-radius(0 0 3px 3px); @@ -215,25 +241,6 @@ h2 .dropdown{ } -footer .actions .dropdown-toggle{ - text-transform:uppercase; - background-color:$color-teal; - line-height:3em; - color:white; - padding-left:1em; - padding-right:1em; - - &:before, - &:after{ - margin:0; - } -} - -footer .actions .dropdown ul li{ - border-bottom:1px solid rgba(255,255,255,0.2); - border-top:0; -} - /* Transitions */ .dropdown ul{ diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/formatters.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/formatters.scss index 569821e107c..150611f8f78 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/formatters.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/formatters.scss @@ -177,4 +177,8 @@ a.tag:hover{ /* make a block-level element inline */ .inline{ display:inline; +} + +.unlist{ + @include unlist(); } \ No newline at end of file diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/listing.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/listing.scss index edf5e65f8d6..e79d8b28dd1 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/listing.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/listing.scss @@ -52,6 +52,7 @@ ul.listing{ } } + /* .dropdown{ padding:0; } @@ -65,6 +66,7 @@ ul.listing{ background-color:white; margin-left:-$grid-gutter-width * 2; } + */ } &.full-width td:first-child, diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss index 8e0894baad6..18c40d2d86f 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss @@ -2,8 +2,11 @@ @import "../mixins.scss"; @import "../grid.scss"; + + section{ border-top:1px solid $color-grey-3; + margin-top:2em; padding:0 0 2em 0; > h2:first-child{ @@ -71,7 +74,15 @@ section{ #icons{ + :before, :after{ + font-size:2em; + } ul{ - @include unlist(); + -webkit-column-count:3; /* Chrome, Safari, Opera */ + -moz-column-count:3; /* Firefox */ + column-count:3; + } + li{ + margin-bottom:1em; } } \ No newline at end of file diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html b/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html index 75f5bcc176e..acb90f138a7 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html @@ -1,6 +1,7 @@ {% extends "wagtailadmin/base.html" %} {% load wagtailadmin_tags %} {% load compress i18n %} +{% load gravatar %} {% block extra_css %} {% compress css %} @@ -16,16 +17,15 @@ {% include "wagtailadmin/shared/header.html" with title=title_trans %}
-

Styleguide

+

Contents

+ + +{% endblock %} + +{% block extra_js %} + {% endblock %} \ No newline at end of file From 5a840c421bc813c71206aff9d4a6ba5172b6939f Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Tue, 13 May 2014 13:05:46 +0100 Subject: [PATCH 021/293] added form icon to font, font icomoon project and styleguide --- .../wagtailadmin/scss/components/icons.scss | 3 + .../scss/fonts/wagtail-icomoon.json | 282 ++++++++++-------- .../wagtailadmin/scss/fonts/wagtail.eot | Bin 25940 -> 26032 bytes .../wagtailadmin/scss/fonts/wagtail.svg | 1 + .../wagtailadmin/scss/fonts/wagtail.ttf | Bin 25776 -> 25868 bytes .../wagtailadmin/scss/fonts/wagtail.woff | Bin 15000 -> 15080 bytes .../wagtailadmin/styleguide/base.html | 1 + 7 files changed, 158 insertions(+), 129 deletions(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/icons.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/icons.scss index 9319d7bd12a..a1aa3cca046 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/icons.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/icons.scss @@ -243,6 +243,9 @@ .icon-date:before{ content:"7"; } +.icon-form:before{ + content:"$"; +} .icon.text-replace{ font-size:0em; line-height:0; diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json index 654e78566a7..fead2733b81 100755 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json @@ -1,6 +1,27 @@ { "IcoMoonType": "selection", "icons": [ + { + "icon": { + "paths": [ + "M102.030 101.608v819.555h819.555v-819.555h-819.555zM352.717 791.689h-165.288v-85.398h301.65v85.398zM792.109 360.562h-604.678v-128.099h603.303v128.099zM790.731 591.965h-603.303v-128.099h603.303v128.099z" + ], + "grid": 0, + "tags": [ + "form" + ] + }, + "properties": { + "order": 1, + "id": 63, + "prevSize": 32, + "code": 36, + "name": "form", + "ligatures": "" + }, + "setIdx": 0, + "iconIdx": 0 + }, { "icon": { "paths": [ @@ -11,14 +32,14 @@ }, "properties": { "id": 0, - "order": 1, + "order": 2, "prevSize": 32, "code": 97, "name": "uni61", "ligatures": "" }, "setIdx": 0, - "iconIdx": 0 + "iconIdx": 1 }, { "icon": { @@ -30,14 +51,14 @@ }, "properties": { "id": 1, - "order": 2, + "order": 3, "prevSize": 32, "code": 98, "name": "uni62", "ligatures": "" }, "setIdx": 0, - "iconIdx": 1 + "iconIdx": 2 }, { "icon": { @@ -49,14 +70,14 @@ }, "properties": { "id": 2, - "order": 3, + "order": 4, "prevSize": 32, "code": 99, "name": "uni63", "ligatures": "" }, "setIdx": 0, - "iconIdx": 2 + "iconIdx": 3 }, { "icon": { @@ -68,14 +89,14 @@ }, "properties": { "id": 3, - "order": 4, + "order": 5, "prevSize": 32, "code": 100, "name": "uni64", "ligatures": "" }, "setIdx": 0, - "iconIdx": 3 + "iconIdx": 4 }, { "icon": { @@ -87,14 +108,14 @@ }, "properties": { "id": 4, - "order": 5, + "order": 6, "prevSize": 32, "code": 101, "name": "uni65", "ligatures": "" }, "setIdx": 0, - "iconIdx": 4 + "iconIdx": 5 }, { "icon": { @@ -106,14 +127,14 @@ }, "properties": { "id": 5, - "order": 6, + "order": 7, "prevSize": 32, "code": 102, "name": "uni66", "ligatures": "" }, "setIdx": 0, - "iconIdx": 5 + "iconIdx": 6 }, { "icon": { @@ -125,14 +146,14 @@ }, "properties": { "id": 6, - "order": 7, + "order": 8, "prevSize": 32, "code": 103, "name": "uni67", "ligatures": "" }, "setIdx": 0, - "iconIdx": 6 + "iconIdx": 7 }, { "icon": { @@ -144,14 +165,14 @@ }, "properties": { "id": 7, - "order": 8, + "order": 9, "prevSize": 32, "code": 105, "name": "uni69", "ligatures": "" }, "setIdx": 0, - "iconIdx": 7 + "iconIdx": 8 }, { "icon": { @@ -163,14 +184,14 @@ }, "properties": { "id": 8, - "order": 9, + "order": 10, "prevSize": 32, "code": 106, "name": "uni6A", "ligatures": "" }, "setIdx": 0, - "iconIdx": 8 + "iconIdx": 9 }, { "icon": { @@ -182,14 +203,14 @@ }, "properties": { "id": 9, - "order": 10, + "order": 11, "prevSize": 32, "code": 107, "name": "uni6B", "ligatures": "" }, "setIdx": 0, - "iconIdx": 9 + "iconIdx": 10 }, { "icon": { @@ -201,14 +222,14 @@ }, "properties": { "id": 10, - "order": 11, + "order": 12, "prevSize": 32, "code": 108, "name": "uni6C", "ligatures": "" }, "setIdx": 0, - "iconIdx": 10 + "iconIdx": 11 }, { "icon": { @@ -220,14 +241,14 @@ }, "properties": { "id": 11, - "order": 12, + "order": 13, "prevSize": 32, "code": 109, "name": "uni6D", "ligatures": "" }, "setIdx": 0, - "iconIdx": 11 + "iconIdx": 12 }, { "icon": { @@ -239,14 +260,14 @@ }, "properties": { "id": 12, - "order": 13, + "order": 14, "prevSize": 32, "code": 110, "name": "uni6E", "ligatures": "" }, "setIdx": 0, - "iconIdx": 12 + "iconIdx": 13 }, { "icon": { @@ -258,14 +279,14 @@ }, "properties": { "id": 13, - "order": 14, + "order": 15, "prevSize": 32, "code": 104, "name": "uni68", "ligatures": "" }, "setIdx": 0, - "iconIdx": 13 + "iconIdx": 14 }, { "icon": { @@ -277,14 +298,14 @@ }, "properties": { "id": 14, - "order": 15, + "order": 16, "prevSize": 32, "code": 111, "name": "uni6F", "ligatures": "" }, "setIdx": 0, - "iconIdx": 14 + "iconIdx": 15 }, { "icon": { @@ -296,14 +317,14 @@ }, "properties": { "id": 15, - "order": 16, + "order": 17, "prevSize": 32, "code": 112, "name": "uni70", "ligatures": "" }, "setIdx": 0, - "iconIdx": 15 + "iconIdx": 16 }, { "icon": { @@ -315,14 +336,14 @@ }, "properties": { "id": 16, - "order": 17, + "order": 18, "prevSize": 32, "code": 113, "name": "uni71", "ligatures": "" }, "setIdx": 0, - "iconIdx": 16 + "iconIdx": 17 }, { "icon": { @@ -334,14 +355,14 @@ }, "properties": { "id": 17, - "order": 18, + "order": 19, "prevSize": 32, "code": 114, "name": "uni72", "ligatures": "" }, "setIdx": 0, - "iconIdx": 17 + "iconIdx": 18 }, { "icon": { @@ -353,14 +374,14 @@ }, "properties": { "id": 18, - "order": 19, + "order": 20, "prevSize": 32, "code": 115, "name": "uni73", "ligatures": "" }, "setIdx": 0, - "iconIdx": 18 + "iconIdx": 19 }, { "icon": { @@ -372,14 +393,14 @@ }, "properties": { "id": 19, - "order": 20, + "order": 21, "prevSize": 32, "code": 116, "name": "uni74", "ligatures": "" }, "setIdx": 0, - "iconIdx": 19 + "iconIdx": 20 }, { "icon": { @@ -391,14 +412,14 @@ }, "properties": { "id": 20, - "order": 21, + "order": 22, "prevSize": 32, "code": 117, "name": "uni75", "ligatures": "" }, "setIdx": 0, - "iconIdx": 20 + "iconIdx": 21 }, { "icon": { @@ -410,14 +431,14 @@ }, "properties": { "id": 21, - "order": 22, + "order": 23, "prevSize": 32, "code": 118, "name": "uni76", "ligatures": "" }, "setIdx": 0, - "iconIdx": 21 + "iconIdx": 22 }, { "icon": { @@ -429,14 +450,14 @@ }, "properties": { "id": 22, - "order": 23, + "order": 24, "prevSize": 32, "code": 119, "name": "uni77", "ligatures": "" }, "setIdx": 0, - "iconIdx": 22 + "iconIdx": 23 }, { "icon": { @@ -448,14 +469,14 @@ }, "properties": { "id": 23, - "order": 24, + "order": 25, "prevSize": 32, "code": 120, "name": "uni78", "ligatures": "" }, "setIdx": 0, - "iconIdx": 23 + "iconIdx": 24 }, { "icon": { @@ -467,14 +488,14 @@ }, "properties": { "id": 24, - "order": 25, + "order": 26, "prevSize": 32, "code": 122, "name": "uni7A", "ligatures": "" }, "setIdx": 0, - "iconIdx": 24 + "iconIdx": 25 }, { "icon": { @@ -486,14 +507,14 @@ }, "properties": { "id": 25, - "order": 26, + "order": 27, "prevSize": 32, "code": 65, "name": "uni41", "ligatures": "" }, "setIdx": 0, - "iconIdx": 25 + "iconIdx": 26 }, { "icon": { @@ -505,14 +526,14 @@ }, "properties": { "id": 26, - "order": 27, + "order": 28, "prevSize": 32, "code": 66, "name": "uni42", "ligatures": "" }, "setIdx": 0, - "iconIdx": 26 + "iconIdx": 27 }, { "icon": { @@ -524,14 +545,14 @@ }, "properties": { "id": 27, - "order": 28, + "order": 29, "prevSize": 32, "code": 68, "name": "uni44", "ligatures": "" }, "setIdx": 0, - "iconIdx": 27 + "iconIdx": 28 }, { "icon": { @@ -543,14 +564,14 @@ }, "properties": { "id": 28, - "order": 29, + "order": 30, "prevSize": 32, "code": 67, "name": "uni43", "ligatures": "" }, "setIdx": 0, - "iconIdx": 28 + "iconIdx": 29 }, { "icon": { @@ -562,14 +583,14 @@ }, "properties": { "id": 29, - "order": 30, + "order": 31, "prevSize": 32, "code": 69, "name": "uni45", "ligatures": "" }, "setIdx": 0, - "iconIdx": 29 + "iconIdx": 30 }, { "icon": { @@ -581,14 +602,14 @@ }, "properties": { "id": 30, - "order": 31, + "order": 32, "prevSize": 32, "code": 70, "name": "uni46", "ligatures": "" }, "setIdx": 0, - "iconIdx": 30 + "iconIdx": 31 }, { "icon": { @@ -600,14 +621,14 @@ }, "properties": { "id": 31, - "order": 32, + "order": 33, "prevSize": 32, "code": 71, "name": "uni47", "ligatures": "" }, "setIdx": 0, - "iconIdx": 31 + "iconIdx": 32 }, { "icon": { @@ -619,14 +640,14 @@ }, "properties": { "id": 32, - "order": 33, + "order": 34, "prevSize": 32, "code": 72, "name": "uni48", "ligatures": "" }, "setIdx": 0, - "iconIdx": 32 + "iconIdx": 33 }, { "icon": { @@ -638,14 +659,14 @@ }, "properties": { "id": 33, - "order": 34, + "order": 35, "prevSize": 32, "code": 73, "name": "uni49", "ligatures": "" }, "setIdx": 0, - "iconIdx": 33 + "iconIdx": 34 }, { "icon": { @@ -657,14 +678,14 @@ }, "properties": { "id": 34, - "order": 35, + "order": 36, "prevSize": 32, "code": 74, "name": "uni4A", "ligatures": "" }, "setIdx": 0, - "iconIdx": 34 + "iconIdx": 35 }, { "icon": { @@ -676,14 +697,14 @@ }, "properties": { "id": 35, - "order": 36, + "order": 37, "prevSize": 32, "code": 75, "name": "uni4B", "ligatures": "" }, "setIdx": 0, - "iconIdx": 35 + "iconIdx": 36 }, { "icon": { @@ -695,14 +716,14 @@ }, "properties": { "id": 36, - "order": 37, + "order": 38, "prevSize": 32, "code": 76, "name": "uni4C", "ligatures": "" }, "setIdx": 0, - "iconIdx": 36 + "iconIdx": 37 }, { "icon": { @@ -714,14 +735,14 @@ }, "properties": { "id": 37, - "order": 38, + "order": 39, "prevSize": 32, "code": 77, "name": "uni4D", "ligatures": "" }, "setIdx": 0, - "iconIdx": 37 + "iconIdx": 38 }, { "icon": { @@ -733,14 +754,14 @@ }, "properties": { "id": 38, - "order": 39, + "order": 40, "prevSize": 32, "code": 78, "name": "uni4E", "ligatures": "" }, "setIdx": 0, - "iconIdx": 38 + "iconIdx": 39 }, { "icon": { @@ -752,14 +773,14 @@ }, "properties": { "id": 39, - "order": 40, + "order": 41, "prevSize": 32, "code": 79, "name": "uni4F", "ligatures": "" }, "setIdx": 0, - "iconIdx": 39 + "iconIdx": 40 }, { "icon": { @@ -771,14 +792,14 @@ }, "properties": { "id": 40, - "order": 41, + "order": 42, "prevSize": 32, "code": 80, "name": "uni50", "ligatures": "" }, "setIdx": 0, - "iconIdx": 40 + "iconIdx": 41 }, { "icon": { @@ -790,14 +811,14 @@ }, "properties": { "id": 41, - "order": 42, + "order": 43, "prevSize": 32, "code": 81, "name": "uni51", "ligatures": "" }, "setIdx": 0, - "iconIdx": 41 + "iconIdx": 42 }, { "icon": { @@ -809,14 +830,14 @@ }, "properties": { "id": 42, - "order": 43, + "order": 44, "prevSize": 32, "code": 121, "name": "uni79", "ligatures": "" }, "setIdx": 0, - "iconIdx": 42 + "iconIdx": 43 }, { "icon": { @@ -828,14 +849,14 @@ }, "properties": { "id": 43, - "order": 44, + "order": 45, "prevSize": 32, "code": 82, "name": "uni52", "ligatures": "" }, "setIdx": 0, - "iconIdx": 43 + "iconIdx": 44 }, { "icon": { @@ -847,14 +868,14 @@ }, "properties": { "id": 44, - "order": 45, + "order": 46, "prevSize": 32, "code": 84, "name": "uni54", "ligatures": "" }, "setIdx": 0, - "iconIdx": 44 + "iconIdx": 45 }, { "icon": { @@ -866,14 +887,14 @@ }, "properties": { "id": 45, - "order": 46, + "order": 47, "prevSize": 32, "code": 87, "name": "uni57", "ligatures": "" }, "setIdx": 0, - "iconIdx": 45 + "iconIdx": 46 }, { "icon": { @@ -885,14 +906,14 @@ }, "properties": { "id": 46, - "order": 47, + "order": 48, "prevSize": 32, "code": 88, "name": "uni58", "ligatures": "" }, "setIdx": 0, - "iconIdx": 46 + "iconIdx": 47 }, { "icon": { @@ -904,14 +925,14 @@ }, "properties": { "id": 47, - "order": 48, + "order": 49, "prevSize": 32, "code": 89, "name": "uni59", "ligatures": "" }, "setIdx": 0, - "iconIdx": 47 + "iconIdx": 48 }, { "icon": { @@ -923,14 +944,14 @@ }, "properties": { "id": 48, - "order": 49, + "order": 50, "prevSize": 32, "code": 90, "name": "uni5A", "ligatures": "" }, "setIdx": 0, - "iconIdx": 48 + "iconIdx": 49 }, { "icon": { @@ -942,14 +963,14 @@ }, "properties": { "id": 49, - "order": 50, + "order": 51, "prevSize": 32, "code": 86, "name": "uni56", "ligatures": "" }, "setIdx": 0, - "iconIdx": 49 + "iconIdx": 50 }, { "icon": { @@ -961,14 +982,14 @@ }, "properties": { "id": 50, - "order": 51, + "order": 52, "prevSize": 32, "code": 49, "name": "uni31", "ligatures": "" }, "setIdx": 0, - "iconIdx": 50 + "iconIdx": 51 }, { "icon": { @@ -980,14 +1001,14 @@ }, "properties": { "id": 51, - "order": 52, + "order": 53, "prevSize": 32, "code": 85, "name": "uni55", "ligatures": "" }, "setIdx": 0, - "iconIdx": 51 + "iconIdx": 52 }, { "icon": { @@ -999,14 +1020,14 @@ }, "properties": { "id": 52, - "order": 53, + "order": 54, "prevSize": 32, "code": 51, "name": "uni33", "ligatures": "" }, "setIdx": 0, - "iconIdx": 52 + "iconIdx": 53 }, { "icon": { @@ -1018,14 +1039,14 @@ }, "properties": { "id": 53, - "order": 54, + "order": 55, "prevSize": 32, "code": 50, "name": "uni32", "ligatures": "" }, "setIdx": 0, - "iconIdx": 53 + "iconIdx": 54 }, { "icon": { @@ -1037,14 +1058,14 @@ }, "properties": { "id": 54, - "order": 55, + "order": 56, "prevSize": 32, "code": 53, "name": "uni35", "ligatures": "" }, "setIdx": 0, - "iconIdx": 54 + "iconIdx": 55 }, { "icon": { @@ -1056,14 +1077,14 @@ }, "properties": { "id": 55, - "order": 56, + "order": 57, "prevSize": 32, "code": 54, "name": "uni36", "ligatures": "" }, "setIdx": 0, - "iconIdx": 55 + "iconIdx": 56 }, { "icon": { @@ -1075,14 +1096,14 @@ }, "properties": { "id": 56, - "order": 57, + "order": 58, "prevSize": 32, "code": 48, "name": "uni30", "ligatures": "" }, "setIdx": 0, - "iconIdx": 56 + "iconIdx": 57 }, { "icon": { @@ -1094,14 +1115,14 @@ }, "properties": { "id": 57, - "order": 58, + "order": 59, "prevSize": 32, "code": 63, "name": "uni3F", "ligatures": "" }, "setIdx": 0, - "iconIdx": 57 + "iconIdx": 58 }, { "icon": { @@ -1113,14 +1134,14 @@ }, "properties": { "id": 58, - "order": 59, + "order": 60, "prevSize": 32, "code": 33, "name": "uni21", "ligatures": "" }, "setIdx": 0, - "iconIdx": 58 + "iconIdx": 59 }, { "icon": { @@ -1132,14 +1153,14 @@ }, "properties": { "id": 59, - "order": 60, + "order": 61, "prevSize": 32, "code": 57, "name": "uni39", "ligatures": "" }, "setIdx": 0, - "iconIdx": 59 + "iconIdx": 60 }, { "icon": { @@ -1151,14 +1172,14 @@ }, "properties": { "id": 60, - "order": 61, + "order": 62, "prevSize": 32, "code": 83, "name": "uni53", "ligatures": "" }, "setIdx": 0, - "iconIdx": 60 + "iconIdx": 61 }, { "icon": { @@ -1170,14 +1191,14 @@ }, "properties": { "id": 61, - "order": 62, + "order": 63, "prevSize": 32, "code": 52, "name": "uni34", "ligatures": "" }, "setIdx": 0, - "iconIdx": 61 + "iconIdx": 62 }, { "icon": { @@ -1189,14 +1210,14 @@ }, "properties": { "id": 62, - "order": 63, + "order": 64, "prevSize": 32, "code": 55, "name": "uni37", "ligatures": "" }, "setIdx": 0, - "iconIdx": 62 + "iconIdx": 63 } ], "height": 1024, @@ -1211,15 +1232,18 @@ "metadata": { "fontFamily": "wagtail", "majorVersion": 1, - "minorVersion": 1 + "minorVersion": 0 }, "metrics": { "emSize": 512, "baseline": 6.25, "whitespace": 50 }, - "embed": false, - "showVersion": true + "includeMetadata": false, + "showMetrics": false, + "showMetadata": false, + "showVersion": false, + "resetPoint": 33 }, "imagePref": {}, "historySize": 100, diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.eot b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.eot index 901b36d6bb81fddc69a64639aa7e2edfe89186a5..c5d6b5cc58b948ee1c15f5abeb6970cb759b23b8 100755 GIT binary patch delta 564 zcmca|igCkfMz#&93=BM}6WPpIUM0`dn&{xeXfV-VbmAhVdd5)3ISdSpG7Jn1CFzO9 z1wdK=$e#eDInr|~(^St#CfWe>X9FPw(Um-6sS2ERrZ^cQV zzy_cO%Yyvk5(Z|V6hq3J$uW%8o(Vvv2+%>y3@i+c42ldY4CV}$4E79B3|0UC{{IhB z$)ErfH2{k`G9-dU8UH{2|M35{|5yKC_<#QYNuX}V$&RVQo3)wL7(H1Sj2VO(&oZtB z8p+AP#~{qWAS|dTs3@##YAkB5XsReG3L=adXZ=g74Vpgv-z7%ff0r3`8Q17bQmjyXrxd2NOgTpRj>;+3 zV`>uWTH%ae_{yGB&26kY;1Ks2@`CjsCMuW+x GQn~;*-I}rh delta 476 zcmdmRn(@jhMz)Yt28InO6WPpI9DH6Zn&{xeXgJYdbmAhVdWI{Ej~EyjWf&M3a?%rv z3xKo$klz8MInr|~)4b0VEdufq%}bKj@-nG0tP>(a|{g0CP2PIUSh6fssaCs zlR$wGpa#o={NfS@W}p;9%7n==jMdH&K&BATLCg$H42%ql4CV}$4E79B3|0UC{{IhB z$DqJq02Xs(NCb;9{(t=c>i;YM&;LL7{{&DU<77o9;mxK@DvX<#GS7{Zlbj_ZHT6h5 zzs*+$ZYHn^=O=nMgBT!sazc{1s54j?N-zRxpgNw-8zS4?y<=u!mSX8+S;2CM zHHNi=Z3(*(2McE$=Q6H7?t8q`_*(e01bzty3H}lC6IvkBAQ~e!Pwbw!n?#YMoYV&C z2W?&xG~Q@7X + diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.ttf b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.ttf index 7e50be989f21b51cc801f25f583b67c6f0d53817..c4161bea849d4ddb060928acbc08627d98cbaa78 100755 GIT binary patch delta 519 zcmdmRlCkF$;{=6z#!$vN3=E7i3=9k<>50V!Kw1FEp8%ve(sL@)RMi)L0P<%rFeET! zq$Z{?_-#vOU`Pb=8O$<(0?dz?RDt{pK)y;wZb?NW1CKY5{{^T=ASXXLQ7M%78UsTz z3sAl*H?g9C!Jp|IkPk9nAulmkGSz@@#Yv#R2A~GZg8bqV248KM}f{{Q{|AEb~$0Vrw!7IkDu1dB5MfBgU9|7-uR{=e}5 z{Qr|c-HZ$jo68u@89iATj2VO(&oZtB8pz4O#~{qWAS|dTs3@##YAkB5XsReG3L=ad zXZ=g74Vpgv-z7%ff0r3`8Q1FwIHU3AEr~3Q^$c5>PBDuxYcV^pY+*Ua@`AOAbsgI& z_6QCw&KAxyTw8cpc=zzF;-4U>AXp)!Bvc}FOk|m8lh_e)7V#X38Imqi*QD#DFUTm# zb|@+-Rw%wx3R7C99HV?k<&^3%H3@Yt^&SlljR;L4%@vwIw03DHXy4LF&}Gn@r1wOB ZodE*_J1~raZgZJzmHe8~V6s|D7XaIIlf(c3 delta 465 zcmeA<#kk=l;{=6zhAWJZ7#J937#J9G(i4jdfV2RR-vOjK(sL@)yw4OZ0`ey?FvM@k zNKH&(aQqm{z>w$ylsC%&3NSxnQUUU7fP9sV+>(lV1|A6@e*sVrPfmVvBF9nLItGTM zH9+}}+{B6k20x~A3=GL8K)ym=Vy8KM}f{{Q{|AEb;yfx!SQ=E#r;7GwPX`2W@aSN@;>fA0SY zpgzXQA5(-kPh?bK+|0;4H%?A+mWnT1)3rH^F=%OTbn)(*BM>_!|coN=7Xxca#7@lNAw;m;EI zB^V_5N61fTfk=aBjMzM}d*W^qMUrw-8>AzoS4sboO;Y%y7^HYY$v~+=*-Uwx$`aKD zs-M)JsHdqv(lF9^quHc+No$I>mG%}LE1g?1Av!-!I|j{0~gqBOdy|4 O-kf}n(QtB8N*4g@bb^!s diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.woff b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.woff index 46fcca86df2ac9f18835a9bff332a42c6dd8132e..484c0b1279783fdfe4d00cef06b333cf25527b9e 100755 GIT binary patch delta 640 zcmbPH`l3{%+~3X3KP1GTfx+qp0~Z4jSS^^m!CZ8rCSSb=1B01IcHXLE{=xc23=HNr zK-mNk=1^icNX|_x0E*24@=HLNF_dvmdSWq9%t8Rj=YV2?jMT&wpqK=ZZwAJG+mbVY zf$ybN6or!DbAJ0wS#*l zuN=Ps|1W`iLe)a2g|mcDi|B|kiQSQqkVunwC1oM?LZ(7CKz6+xpZsCvBIVmE1uEZE z!__#|rmOGNxT?VI;>a^eY z!%?*RkKPZx?(QFYfAqRpzYG3;D{9%@z3sbpcXtBockS;vqQ4Jycc1=#u)Euvwfi@R z=x-nk%H3SSTyH%2r&*b60?_Xw3<3sl^C;~&-oWYX8o*{~%>i^&W|ADd$3<^L| z1F)zgLn2s|@&Duh5C32LfA#-`|L6aooV?ClTo)LW42(b>{6HGSX3(0K{3@Q`<|_j? x6WEyZ(|274F+lX>59a2QE?{9O0n!9i#{iGP+E*vb@Y_FqzM)3jo!evTXnW delta 567 zcmaD+I-^vg+~3X3KP1GTfx&790~Z4jSOqXJGB8fQXeBaHhr6DMfx(Q)@Omwef3Ut0 zko^OwA_0Usl-LcDa}x^~7|bJp{2Va8!uTjXu^1$F1jy%rVu6g*#1x>|86e*bj2%D5 zW&i~l7%W(Td=(I8e#E4bky}y$6w_c}VB`VedIlpNiQL2rpn;YqKt*g|>>R+5mzbLh z6te*;vIJoR{uL(+@{3D=uCJK*!c#PdUlu4_C7^%mnl&3j;gQ*Sri}OdFWlnYEd{SvIiTXXR!6#Ad=C&i;qvI+q?-1$QRTJ-!S4 zy9DM5SqpUwYYBG?zY#qoHb?x1gqp-E$sbZHWGrL_WbVmnS6and|FsiztaTphI_a6{eb?vhHBd6RY*b`)(Ri-$zscX2IydiUt}|w2 zm~3NS?hFc0AqD{kW(JTO6&cJKEE((>q8O_F|NZ|TD96B{z+eCtb7V*ai!uIx{Qv6z zEC0{`KllFxP#-A%gtdY32vpAxGy@nKlCu`Q@NtOexB1Gz4UAPFI6u+58AeaGu`m~P e1`9(8kS3ryp2Icons
  • warning
  • success
  • date
  • +
  • form
  • From bc99de529be8259e71a334fb4295f775233b10e7 Mon Sep 17 00:00:00 2001 From: Robert Clark Date: Tue, 13 May 2014 12:46:20 -0400 Subject: [PATCH 022/293] page type business rules --- wagtail/tests/models.py | 12 +++++++ .../wagtailadmin/pages/add_subpage.html | 4 +-- wagtail/wagtailadmin/tests.py | 35 ++++++++++++++++++- wagtail/wagtailadmin/views/pages.py | 4 +-- wagtail/wagtailcore/models.py | 10 ++++-- 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/wagtail/tests/models.py b/wagtail/tests/models.py index 9124cb253de..6c4b45f31c8 100644 --- a/wagtail/tests/models.py +++ b/wagtail/tests/models.py @@ -196,3 +196,15 @@ def get_context(self, request): FieldPanel('title', classname="full title"), FieldPanel('intro', classname="full"), ] + +class StandardIndex(Page): + pass + +class StandardChild(Page): + pass + +class BusinessIndex(Page): + subpage_types = ['tests.BusinessChild'] + +class BusinessChild(Page): + pass diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/add_subpage.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/add_subpage.html index 757c013b5cb..1158cc857ee 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/add_subpage.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/add_subpage.html @@ -12,9 +12,9 @@

    {% trans "Choose which type of page you'd like to create." %}

    - {% if all_page_types %} + {% if page_types %}
      - {% for content_type in all_page_types %} + {% for content_type in page_types %}
    • diff --git a/wagtail/wagtailadmin/tests.py b/wagtail/wagtailadmin/tests.py index 435f29a9c19..59e112b32c6 100644 --- a/wagtail/wagtailadmin/tests.py +++ b/wagtail/wagtailadmin/tests.py @@ -1,6 +1,6 @@ from django.test import TestCase import unittest2 as unittest -from wagtail.tests.models import SimplePage, EventPage +from wagtail.tests.models import SimplePage, EventPage, StandardIndex, StandardChild, BusinessIndex, BusinessChild from wagtail.tests.utils import login from wagtail.wagtailcore.models import Page from django.core.urlresolvers import reverse @@ -326,3 +326,36 @@ def test_editor_css_and_js_hooks_on_edit(self): self.assertEqual(response.status_code, 200) self.assertContains(response, '') self.assertContains(response, '') + + +class TestSubpageBusinessRules(TestCase): + def setUp(self): + # Find root page + self.root_page = Page.objects.get(id=2) + + # Add standard page + self.standard_index = StandardIndex() + self.standard_index.title = "Standard Index" + self.standard_index.slug = "standard-index" + self.root_page.add_child(instance=self.standard_index) + + # Add business page + self.business_index = BusinessIndex() + self.business_index.title = "Business Index" + self.business_index.slug = "business-index" + self.root_page.add_child(instance=self.business_index) + + # Login + login(self.client) + + def test_standard_subpage(self): + response = self.client.get(reverse('wagtailadmin_pages_add_subpage', args=(self.standard_index.id, ))) + self.assertEqual(response.status_code, 200) + self.assertContains(response, 'Standard Child') + self.assertContains(response, 'Business Child') + + def test_business_subpage(self): + response = self.client.get(reverse('wagtailadmin_pages_add_subpage', args=(self.business_index.id, ))) + self.assertEqual(response.status_code, 200) + self.assertNotContains(response, 'Standard Child') + self.assertContains(response, 'Business Child') diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index 6be731c3b9a..56c1294f9c1 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -68,13 +68,11 @@ def add_subpage(request, parent_page_id): if not parent_page.permissions_for_user(request.user).can_add_subpage(): raise PermissionDenied - page_types = sorted([ContentType.objects.get_for_model(model_class) for model_class in parent_page.clean_subpage_types()], key=lambda pagetype: pagetype.name.lower()) - all_page_types = sorted(get_page_types(), key=lambda pagetype: pagetype.name.lower()) + page_types = sorted(parent_page.clean_subpage_types(), key=lambda pagetype: pagetype.name.lower()) return render(request, 'wagtailadmin/pages/add_subpage.html', { 'parent_page': parent_page, 'page_types': page_types, - 'all_page_types': all_page_types, }) diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index 441c74a2821..0fc1b3350a7 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -484,7 +484,11 @@ def clean_subpage_types(cls): where required """ if cls._clean_subpage_types is None: - res = [] + if len(cls.subpage_types) == 0: + res = get_page_types() + else: + res = [] + for page_type in cls.subpage_types: if isinstance(page_type, basestring): try: @@ -496,13 +500,13 @@ def clean_subpage_types(cls): model = get_model(app_label, model_name) if model: - res.append(model) + res.append(ContentType.objects.get_for_model(model)) else: raise NameError(_("name '{0}' (used in subpage_types list) is not defined.").format(page_type)) else: # assume it's already a model class - res.append(page_type) + res.append(ContentType.objects.get_for_model(page_type)) cls._clean_subpage_types = res From d7c5a06929dbb175482ad92b17e9f87342966c1c Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 23 May 2014 12:02:37 +0100 Subject: [PATCH 023/293] updated icons --- .../wagtailadmin/scss/components/icons.scss | 6 -- .../wagtailadmin/scss/fonts/wagtail.eot | Bin 26032 -> 26032 bytes .../wagtailadmin/scss/fonts/wagtail.svg | 71 +----------------- .../wagtailadmin/scss/fonts/wagtail.ttf | Bin 25868 -> 25868 bytes .../wagtailadmin/scss/fonts/wagtail.woff | Bin 15080 -> 15080 bytes 5 files changed, 1 insertion(+), 76 deletions(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/icons.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/icons.scss index 7fb3320dd8d..92e83bbe5c3 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/icons.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/icons.scss @@ -246,12 +246,6 @@ .icon-form:before{ content:"$"; } -.icon-date:before{ - content:"7"; -} -.icon-form:before{ - content:"$"; -} .icon.text-replace{ font-size:0em; line-height:0; diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.eot b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.eot index c5d6b5cc58b948ee1c15f5abeb6970cb759b23b8..7d7860a83289d44e2dc32b0b001995f293d6a15c 100755 GIT binary patch delta 57 zcmdmRnsLKv#tAme%N}J;wBN>@@tt+!51&LCgD)Oc@%%Pl8Mv7kK;Zn6+bS@6b3#%8 FGXSQ16;=QM delta 57 zcmdmRnsLKv#tAmeuaf6YwBN?;w=H?&51&LCLyeRB;`wd9GH^37fWZ0byDr1%%?U{X F%mA%N7Eb^G diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg index f25359ec600..dcfa5a08c60 100755 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg @@ -6,7 +6,6 @@ -<<<<<<< HEAD @@ -72,72 +71,4 @@ - -======= - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->>>>>>> master + \ No newline at end of file diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.ttf b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.ttf index c4161bea849d4ddb060928acbc08627d98cbaa78..38d2e1789c3dbff85017292ac2372a17f1b970bb 100755 GIT binary patch delta 50 xcmeA<#n^L-aY7(-#&_0@AwG#R246g?;`wd9GH^37fWY}Bw^d;D<~@l4%mB<)5nccQ delta 50 ycmeA<#n^L-aY7)o-?rq9AwG#Rh8idL#q-;IW#DFF0D<${i2(%8FS)G(qc_`FtYHEG*xM1g delta 47 vcmaD+`l56~FSFma{i2(%8Pv3PJMsK#USi=MW;jI$5 From c7921f2cda3afeaba695e46e61317e8d7d6d8598 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 23 May 2014 12:07:21 +0100 Subject: [PATCH 024/293] updated green colour for messages --- .../static/wagtailadmin/scss/components/messages.scss | 2 +- wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/messages.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/messages.scss index e5e2454f694..ff01dc248e5 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/messages.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/messages.scss @@ -40,7 +40,7 @@ } } .success{ - background-color:$color-teal-dark; + background-color:$color-green; &:before{ font-family:wagtail; diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss index 4c06efec8bd..0f65679893f 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss @@ -29,7 +29,7 @@ $color-teal-darker: darken($color-teal, 10%); $color-teal-dark: #246060; $color-red: #f7474e; $color-orange:#e9b04d; -$color-green: #00FF00; +$color-green: #189370; /* darker to lighter */ $color-grey-1: #333333; From 9511b21ea73cf86958c8221eec212bd04c18198d Mon Sep 17 00:00:00 2001 From: Serafeim Papastefanos Date: Sun, 25 May 2014 22:07:59 +0300 Subject: [PATCH 025/293] Test publish scheduled pages management command --- wagtail/wagtailadmin/tests.py | 154 +++++++++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 3 deletions(-) diff --git a/wagtail/wagtailadmin/tests.py b/wagtail/wagtailadmin/tests.py index 3df92ec2247..04bf38f7639 100644 --- a/wagtail/wagtailadmin/tests.py +++ b/wagtail/wagtailadmin/tests.py @@ -1,11 +1,13 @@ from datetime import datetime, timedelta +from django.core import management +from django.core.urlresolvers import reverse from django.utils import timezone from django.test import TestCase import unittest +from StringIO import StringIO from wagtail.tests.models import SimplePage, EventPage from wagtail.tests.utils import login from wagtail.wagtailcore.models import Page, PageRevision -from django.core.urlresolvers import reverse class TestHome(TestCase): @@ -127,7 +129,7 @@ def test_create_simplepage_scheduled(self): # No revisions with approved_go_live_datetime self.assertFalse(PageRevision.objects.filter(page=page).exclude(approved_go_live_datetime__isnull=True).exists()) - def test_create_simplepage_scheduled_errored(self): + def test_create_simplepage_scheduled_go_live_before_expiry(self): post_data = { 'title': "New page!", 'content': "Some content", @@ -141,6 +143,7 @@ def test_create_simplepage_scheduled_errored(self): self.assertEqual(response.status_code, 200) self.assertTrue(response.context['edit_handler'].form.errors) + def test_create_simplepage_scheduled_expire_in_the_past(self): post_data = { 'title': "New page!", 'content': "Some content", @@ -337,9 +340,51 @@ def test_edit_post_publish_scheduled(self): child_page_new = SimplePage.objects.get(id=self.child_page.id) # The page should not be live anymore self.assertFalse(child_page_new.live) - # Instead a revision with approved_go_live_datetime should not exist + # Instead a revision with approved_go_live_datetime should now exist self.assertTrue(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_datetime__isnull=True).exists()) + def test_edit_post_publish_now_an_already_scheduled(self): + # First let's publish a page with a go_live_datetime in the future + go_live_datetime = timezone.now() + timedelta(days=1) + expiry_datetime = timezone.now() + timedelta(days=2) + post_data = { + 'title': "I've been edited!", + 'content': "Some content", + 'slug': 'hello-world', + 'action-publish': "Publish", + 'go_live_datetime': str(go_live_datetime), + 'expiry_datetime': str(expiry_datetime), + } + response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data) + + # Should be redirected to explorer page + self.assertEqual(response.status_code, 302) + + child_page_new = SimplePage.objects.get(id=self.child_page.id) + # The page should not be live anymore + self.assertFalse(child_page_new.live) + # Instead a revision with approved_go_live_datetime should now exist + self.assertTrue(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_datetime__isnull=True).exists()) + + # Now, let's edit it and publish it right now + go_live_datetime = timezone.now() + post_data = { + 'title': "I've been edited!", + 'content': "Some content", + 'slug': 'hello-world', + 'action-publish': "Publish", + 'go_live_datetime': "", + } + response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data) + + # Should be redirected to explorer page + self.assertEqual(response.status_code, 302) + + child_page_new = SimplePage.objects.get(id=self.child_page.id) + # The page should be live now + self.assertTrue(child_page_new.live) + # And a revision with approved_go_live_datetime should not exist + self.assertFalse(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_datetime__isnull=True).exists()) class TestPageDelete(TestCase): def setUp(self): @@ -454,3 +499,106 @@ def test_editor_css_and_js_hooks_on_edit(self): self.assertEqual(response.status_code, 200) self.assertContains(response, '') self.assertContains(response, '') + +class TestPublishScheduledPages(TestCase): + def setUp(self): + # Find root page + self.root_page = Page.objects.get(id=2) + + def test_go_live_page_will_be_published(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = False + page.go_live_datetime = timezone.now() - timedelta(days=1) + self.root_page.add_child(page) + + page.save_revision( + approved_go_live_datetime = timezone.now() - timedelta(days=1) + ) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + management.call_command('publish_scheduled_pages', verbosity=3, interactive=False) + #management.call_command('publish_scheduled_pages', dryrun=True, verbosity=3, interactive=False) + p = Page.objects.get(slug='hello-world') + self.assertTrue(p.live) + self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + + def test_go_live_page_will_be_published(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = False + page.go_live_datetime = timezone.now() - timedelta(days=1) + self.root_page.add_child(page) + + page.save_revision(approved_go_live_datetime = timezone.now() - timedelta(days=1)) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + management.call_command('publish_scheduled_pages', ) + p = Page.objects.get(slug='hello-world') + self.assertTrue(p.live) + self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + + def test_future_go_live_page_will_not_be_published(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = False + page.go_live_datetime = timezone.now() + timedelta(days=1) + self.root_page.add_child(page) + page.save_revision(approved_go_live_datetime = timezone.now() - timedelta(days=1)) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + management.call_command('publish_scheduled_pages', ) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + + def test_expired_page_will_be_unpublished(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = True + page.expiry_datetime = timezone.now() - timedelta(days=1) + self.root_page.add_child(page) + p = Page.objects.get(slug='hello-world') + self.assertTrue(p.live) + management.call_command('publish_scheduled_pages', ) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(p.expired) + + def test_future_expired_page_will_not_be_unpublished(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = True + page.expiry_datetime = timezone.now() + timedelta(days=1) + self.root_page.add_child(page) + p = Page.objects.get(slug='hello-world') + self.assertTrue(p.live) + management.call_command('publish_scheduled_pages', ) + p = Page.objects.get(slug='hello-world') + self.assertTrue(p.live) + self.assertFalse(p.expired) + + def test_expired_pages_are_dropped_from_mod_queue(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = False + page.expiry_datetime = timezone.now() - timedelta(days=1) + self.root_page.add_child(page) + page.save_revision(submitted_for_moderation = True) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(PageRevision.objects.filter(page=p, submitted_for_moderation=True).exists()) + management.call_command('publish_scheduled_pages', ) + p = Page.objects.get(slug='hello-world') + self.assertFalse(PageRevision.objects.filter(page=p, submitted_for_moderation=True).exists()) + + From 8dfd0c623f7dfa954e7f5c6307da06213932e4e7 Mon Sep 17 00:00:00 2001 From: Serafeim Papastefanos Date: Thu, 29 May 2014 19:03:19 +0300 Subject: [PATCH 026/293] Add help_text mssage to scheduled publisihing ... datetime fields (go_live_datetime and expiry_datetime) to help users fill them since no datetim control is available. --- wagtail/wagtailcore/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index 5bdf1c37304..434b174b646 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -235,8 +235,8 @@ class Page(MP_Node, ClusterableModel, Indexed): show_in_menus = models.BooleanField(default=False, help_text=_("Whether a link to this page will appear in automatically generated menus")) search_description = models.TextField(blank=True) - go_live_datetime = models.DateTimeField(verbose_name=_("Go live date/time"), blank=True, null=True) - expiry_datetime = models.DateTimeField(verbose_name=_("Expiry date/time"), blank=True, null=True) + go_live_datetime = models.DateTimeField(verbose_name=_("Go live date/time"), help_text=_("Please add a date-time in the form YYYY-MM-DD hh:mm."), blank=True, null=True) + expiry_datetime = models.DateTimeField(verbose_name=_("Expiry date/time"), help_text=_("Please add a date-time in the form YYYY-MM-DD hh:mm."), blank=True, null=True) expired = models.BooleanField(default=False, editable=False) indexed_fields = { From 7ba7ded7c6cf2183f7ba4dbee80c86ede90d00cb Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 2 Jun 2014 13:40:34 +0100 Subject: [PATCH 027/293] Added WagtailTestCase class with a couple of useful methods --- wagtail/tests/utils.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/wagtail/tests/utils.py b/wagtail/tests/utils.py index 6590e6dcc51..8e18c661dc9 100644 --- a/wagtail/tests/utils.py +++ b/wagtail/tests/utils.py @@ -1,4 +1,6 @@ +from django.test import TestCase from django.contrib.auth.models import User +from django.utils.six.moves.urllib.parse import urlparse, ParseResult # We need to make sure that we're using the same unittest library that Django uses internally # Otherwise, we get issues with the "SkipTest" and "ExpectedFailure" exceptions being recognised as errors @@ -20,3 +22,26 @@ def login(client): client.login(username='test', password='password') return user + + +class WagtailTestCase(TestCase): + def login(self): + login(self.client) + + # From: https://github.com/django/django/blob/255449c1ee61c14778658caae8c430fa4d76afd6/django/contrib/auth/tests/test_views.py#L70-L85 + def assertURLEqual(self, url, expected, parse_qs=False): + """ + Given two URLs, make sure all their components (the ones given by + urlparse) are equal, only comparing components that are present in both + URLs. + If `parse_qs` is True, then the querystrings are parsed with QueryDict. + This is useful if you don't want the order of parameters to matter. + Otherwise, the query strings are compared as-is. + """ + fields = ParseResult._fields + + for attr, x, y in zip(fields, urlparse(url), urlparse(expected)): + if parse_qs and attr == 'query': + x, y = QueryDict(x), QueryDict(y) + if x and y and x != y: + self.fail("%r != %r (%s doesn't match)" % (url, expected, attr)) From 7e7910ba3b68e524683f4bafda08983805f11708 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 2 Jun 2014 13:41:00 +0100 Subject: [PATCH 028/293] Added LOGIN_REDIRECT_URL to runtests.py settings --- runtests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtests.py b/runtests.py index 6fd37ebeb84..346729653f2 100755 --- a/runtests.py +++ b/runtests.py @@ -101,7 +101,8 @@ ), COMPRESS_ENABLED=False, # disable compression so that we can run tests on the content of the compress tag WAGTAILSEARCH_BACKENDS=WAGTAILSEARCH_BACKENDS, - WAGTAIL_SITE_NAME='Test Site' + WAGTAIL_SITE_NAME='Test Site', + LOGIN_REDIRECT_URL = 'wagtailadmin_home', ) From 765f90746a6fac9e3a0caff025e0d668aed23a5d Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 2 Jun 2014 13:41:28 +0100 Subject: [PATCH 029/293] Use new WagtailTestCase class for checking redirect URLs in account management tests --- .../tests/test_account_management.py | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/wagtail/wagtailadmin/tests/test_account_management.py b/wagtail/wagtailadmin/tests/test_account_management.py index 95d54d7d936..0b71d55fbe6 100644 --- a/wagtail/wagtailadmin/tests/test_account_management.py +++ b/wagtail/wagtailadmin/tests/test_account_management.py @@ -1,17 +1,16 @@ -from django.test import TestCase -from wagtail.tests.utils import login, unittest +from wagtail.tests.utils import unittest, WagtailTestCase from django.core.urlresolvers import reverse from django.contrib.auth.models import User from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.core import mail -class TestAuthentication(TestCase): +class TestAuthentication(WagtailTestCase): """ This tests that users can login and logout of the admin interface """ def setUp(self): - login(self.client) + self.login() def test_login_view(self): """ @@ -44,6 +43,7 @@ def test_login_view_post(self): # Check that the user was redirected to the dashboard self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_home')) # Check that the user was logged in self.assertTrue('_auth_user_id' in self.client.session) @@ -61,6 +61,7 @@ def test_already_logged_in_redirect(self): # Check that the user was redirected to the dashboard self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_home')) def test_logout(self): """ @@ -71,17 +72,18 @@ def test_logout(self): # Check that the user was redirected to the login page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_login')) # Check that the user was logged out self.assertFalse('_auth_user_id' in self.client.session) -class TestAccountSection(TestCase): +class TestAccountSection(WagtailTestCase): """ This tests that the accounts section is working """ def setUp(self): - login(self.client) + self.login() def test_account_view(self): """ @@ -117,8 +119,9 @@ def test_change_password_view_post(self): } response = self.client.post(reverse('wagtailadmin_account_change_password'), post_data) - # Check that the user was redirected + # Check that the user was redirected to the account page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_account')) # Check that the password was changed self.assertTrue(User.objects.get(username='test').check_password('newpassword')) @@ -146,7 +149,7 @@ def test_change_password_view_post_password_mismatch(self): self.assertTrue(User.objects.get(username='test').check_password('password')) -class TestPasswordReset(TestCase): +class TestPasswordReset(WagtailTestCase): """ This tests that the password reset is working """ @@ -176,8 +179,9 @@ def test_password_reset_view_post(self): } response = self.client.post(reverse('password_reset'), post_data) - # Check that the user was redirected + # Check that the user was redirected to the done page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('password_reset_done')) # Check that a password reset email was sent to the user self.assertEqual(len(mail.outbox), 1) @@ -267,8 +271,9 @@ def test_password_reset_confirm_view_post(self): } response = self.client.post(reverse('password_reset_confirm', kwargs=self.url_kwargs), post_data) - # Check that the user was redirected + # Check that the user was redirected to the complete page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('password_reset_complete')) # Check that the password was changed self.assertTrue(User.objects.get(username='test').check_password('newpassword')) From a8ca4f14daefd980b402d987cd6fb7c496d991c4 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 2 Jun 2014 13:56:19 +0100 Subject: [PATCH 030/293] Return user object from login method --- wagtail/tests/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wagtail/tests/utils.py b/wagtail/tests/utils.py index 8e18c661dc9..44e61255508 100644 --- a/wagtail/tests/utils.py +++ b/wagtail/tests/utils.py @@ -26,7 +26,7 @@ def login(client): class WagtailTestCase(TestCase): def login(self): - login(self.client) + return login(self.client) # From: https://github.com/django/django/blob/255449c1ee61c14778658caae8c430fa4d76afd6/django/contrib/auth/tests/test_views.py#L70-L85 def assertURLEqual(self, url, expected, parse_qs=False): From 00a06856a8fba6ef838ac41e4a261d9e03d4698a Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 2 Jun 2014 13:56:54 +0100 Subject: [PATCH 031/293] Use WagtailTestCase class in admin page views tests --- .../wagtailadmin/tests/test_pages_views.py | 59 +++++++++++-------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/wagtail/wagtailadmin/tests/test_pages_views.py b/wagtail/wagtailadmin/tests/test_pages_views.py index ccaa67daeef..f97c2658187 100644 --- a/wagtail/wagtailadmin/tests/test_pages_views.py +++ b/wagtail/wagtailadmin/tests/test_pages_views.py @@ -1,13 +1,12 @@ -from django.test import TestCase from wagtail.tests.models import SimplePage, EventPage -from wagtail.tests.utils import login, unittest +from wagtail.tests.utils import unittest, WagtailTestCase from wagtail.wagtailcore.models import Page, PageRevision from django.core.urlresolvers import reverse from django.contrib.auth.models import User, Permission from django.core import mail -class TestPageExplorer(TestCase): +class TestPageExplorer(WagtailTestCase): def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) @@ -19,7 +18,7 @@ def setUp(self): self.root_page.add_child(instance=self.child_page) # Login - login(self.client) + self.login() def test_explore(self): response = self.client.get(reverse('wagtailadmin_explore', args=(self.root_page.id, ))) @@ -28,13 +27,13 @@ def test_explore(self): self.assertTrue(response.context['pages'].filter(id=self.child_page.id).exists()) -class TestPageCreation(TestCase): +class TestPageCreation(WagtailTestCase): def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) # Login - self.user = login(self.client) + self.user = self.login() def test_add_subpage(self): response = self.client.get(reverse('wagtailadmin_pages_add_subpage', args=(self.root_page.id, ))) @@ -86,6 +85,7 @@ def test_create_simplepage_post(self): # Should be redirected to explorer page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_explore', args=(self.root_page.id, ))) # Find the page and check it page = Page.objects.get(path__startswith=self.root_page.path, slug='hello-world').specific @@ -104,6 +104,7 @@ def test_create_simplepage_post_publish(self): # Should be redirected to explorer page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_explore', args=(self.root_page.id, ))) # Find the page and check it page = Page.objects.get(path__startswith=self.root_page.path, slug='hello-world').specific @@ -126,6 +127,7 @@ def test_create_simplepage_post_submit(self): # Should be redirected to explorer page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_explore', args=(self.root_page.id, ))) # Find the page and check it page = Page.objects.get(path__startswith=self.root_page.path, slug='hello-world').specific @@ -186,7 +188,7 @@ def test_preview_on_create(self): self.assertContains(response, "New page!") -class TestPageEdit(TestCase): +class TestPageEdit(WagtailTestCase): def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) @@ -206,7 +208,7 @@ def setUp(self): self.root_page.add_child(instance=self.event_page) # Login - self.user = login(self.client) + self.user = self.login() def test_page_edit(self): # Tests that the edit page loads @@ -238,6 +240,7 @@ def test_page_edit_post(self): # Should be redirected to explorer page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_explore', args=(self.root_page.id, ))) # The page should have "has_unpublished_changes" flag set child_page_new = SimplePage.objects.get(id=self.child_page.id) @@ -255,6 +258,7 @@ def test_page_edit_post_publish(self): # Should be redirected to explorer page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_explore', args=(self.root_page.id, ))) # Check that the page was edited child_page_new = SimplePage.objects.get(id=self.child_page.id) @@ -278,6 +282,7 @@ def test_page_edit_post_submit(self): # Should be redirected to explorer page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_explore', args=(self.root_page.id, ))) # The page should have "has_unpublished_changes" flag set child_page_new = SimplePage.objects.get(id=self.child_page.id) @@ -306,7 +311,7 @@ def test_preview_on_edit(self): self.assertContains(response, "I've been edited!") -class TestPageDelete(TestCase): +class TestPageDelete(WagtailTestCase): def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) @@ -318,7 +323,7 @@ def setUp(self): self.root_page.add_child(instance=self.child_page) # Login - self.user = login(self.client) + self.user = self.login() def test_page_delete(self): response = self.client.get(reverse('wagtailadmin_pages_delete', args=(self.child_page.id, ))) @@ -344,15 +349,16 @@ def test_page_delete_post(self): # Should be redirected to explorer page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_explore', args=(self.root_page.id, ))) # Check that the page is gone self.assertEqual(Page.objects.filter(path__startswith=self.root_page.path, slug='hello-world').count(), 0) -class TestPageSearch(TestCase): +class TestPageSearch(WagtailTestCase): def setUp(self): # Login - login(self.client) + self.login() def get(self, params=None, **extra): return self.client.get(reverse('wagtailadmin_pages_search'), params or {}, **extra) @@ -390,7 +396,7 @@ def test_root_can_appear_in_search_results(self): self.assertTrue(any([r.slug == 'root' for r in results])) -class TestPageMove(TestCase): +class TestPageMove(WagtailTestCase): def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) @@ -413,7 +419,7 @@ def setUp(self): self.section_a.add_child(instance=self.test_page) # Login - self.user = login(self.client) + self.user = self.login() def test_page_move(self): response = self.client.get(reverse('wagtailadmin_pages_move', args=(self.test_page.id, ))) @@ -442,18 +448,18 @@ def test_page_set_page_position(self): self.assertEqual(response.status_code, 200) -class TestPageUnpublish(TestCase): +class TestPageUnpublish(WagtailTestCase): def setUp(self): - self.user = login(self.client) + self.user = self.login() # Create a page to unpublish - root_page = Page.objects.get(id=2) + self.root_page = Page.objects.get(id=2) self.page = SimplePage( title="Hello world!", slug='hello-world', live=True, ) - root_page.add_child(instance=self.page) + self.root_page.add_child(instance=self.page) def test_unpublish_view(self): """ @@ -502,14 +508,15 @@ def test_unpublish_view_post(self): 'foo': "Must post something or the view won't see this as a POST request", }) - # Check that the user was redirected + # Check that the user was redirected to the explore page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_explore', args=(self.root_page.id, ))) # Check that the page was unpublished self.assertFalse(SimplePage.objects.get(id=self.page.id).live) -class TestApproveRejectModeration(TestCase): +class TestApproveRejectModeration(WagtailTestCase): def setUp(self): self.submitter = User.objects.create_superuser( username='submitter', @@ -517,7 +524,7 @@ def setUp(self): password='password', ) - self.user = login(self.client) + self.user = self.login() # Create a page and submit it for moderation root_page = Page.objects.get(id=2) @@ -540,8 +547,9 @@ def test_approve_moderation_view(self): 'foo': "Must post something or the view won't see this as a POST request", }) - # Check that the user was redirected + # Check that the user was redirected to the dashboard self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_home')) # Page must be live self.assertTrue(Page.objects.get(id=self.page.id).live) @@ -591,8 +599,9 @@ def test_reject_moderation_view(self): 'foo': "Must post something or the view won't see this as a POST request", }) - # Check that the user was redirected + # Check that the user was redirected to the dashboard self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_home')) # Page must not be live self.assertFalse(Page.objects.get(id=self.page.id).live) @@ -645,11 +654,11 @@ def test_preview_for_moderation(self): self.assertContains(response, "Hello world!") -class TestContentTypeUse(TestCase): +class TestContentTypeUse(WagtailTestCase): fixtures = ['test.json'] def setUp(self): - self.user = login(self.client) + self.user = self.login() def test_content_type_use(self): # Get use of event page From 301fd6ec3c5e37b8f9b092fade08e49c7bde949c Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 2 Jun 2014 13:59:06 +0100 Subject: [PATCH 032/293] Made WagtailTestCase a mixin and renamed to WagtailTestUtils. --- wagtail/tests/utils.py | 2 +- .../tests/test_account_management.py | 9 ++++---- .../wagtailadmin/tests/test_pages_views.py | 21 ++++++++++--------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/wagtail/tests/utils.py b/wagtail/tests/utils.py index 44e61255508..4b22b000c53 100644 --- a/wagtail/tests/utils.py +++ b/wagtail/tests/utils.py @@ -24,7 +24,7 @@ def login(client): return user -class WagtailTestCase(TestCase): +class WagtailTestUtils(object): def login(self): return login(self.client) diff --git a/wagtail/wagtailadmin/tests/test_account_management.py b/wagtail/wagtailadmin/tests/test_account_management.py index 0b71d55fbe6..499cd9554d6 100644 --- a/wagtail/wagtailadmin/tests/test_account_management.py +++ b/wagtail/wagtailadmin/tests/test_account_management.py @@ -1,11 +1,12 @@ -from wagtail.tests.utils import unittest, WagtailTestCase +from django.test import TestCase +from wagtail.tests.utils import unittest, WagtailTestUtils from django.core.urlresolvers import reverse from django.contrib.auth.models import User from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.core import mail -class TestAuthentication(WagtailTestCase): +class TestAuthentication(TestCase, WagtailTestUtils): """ This tests that users can login and logout of the admin interface """ @@ -78,7 +79,7 @@ def test_logout(self): self.assertFalse('_auth_user_id' in self.client.session) -class TestAccountSection(WagtailTestCase): +class TestAccountSection(TestCase, WagtailTestUtils): """ This tests that the accounts section is working """ @@ -149,7 +150,7 @@ def test_change_password_view_post_password_mismatch(self): self.assertTrue(User.objects.get(username='test').check_password('password')) -class TestPasswordReset(WagtailTestCase): +class TestPasswordReset(TestCase, WagtailTestUtils): """ This tests that the password reset is working """ diff --git a/wagtail/wagtailadmin/tests/test_pages_views.py b/wagtail/wagtailadmin/tests/test_pages_views.py index f97c2658187..a34b29fd894 100644 --- a/wagtail/wagtailadmin/tests/test_pages_views.py +++ b/wagtail/wagtailadmin/tests/test_pages_views.py @@ -1,12 +1,13 @@ +from django.test import TestCase from wagtail.tests.models import SimplePage, EventPage -from wagtail.tests.utils import unittest, WagtailTestCase +from wagtail.tests.utils import unittest, WagtailTestUtils from wagtail.wagtailcore.models import Page, PageRevision from django.core.urlresolvers import reverse from django.contrib.auth.models import User, Permission from django.core import mail -class TestPageExplorer(WagtailTestCase): +class TestPageExplorer(TestCase, WagtailTestUtils): def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) @@ -27,7 +28,7 @@ def test_explore(self): self.assertTrue(response.context['pages'].filter(id=self.child_page.id).exists()) -class TestPageCreation(WagtailTestCase): +class TestPageCreation(TestCase, WagtailTestUtils): def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) @@ -188,7 +189,7 @@ def test_preview_on_create(self): self.assertContains(response, "New page!") -class TestPageEdit(WagtailTestCase): +class TestPageEdit(TestCase, WagtailTestUtils): def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) @@ -311,7 +312,7 @@ def test_preview_on_edit(self): self.assertContains(response, "I've been edited!") -class TestPageDelete(WagtailTestCase): +class TestPageDelete(TestCase, WagtailTestUtils): def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) @@ -355,7 +356,7 @@ def test_page_delete_post(self): self.assertEqual(Page.objects.filter(path__startswith=self.root_page.path, slug='hello-world').count(), 0) -class TestPageSearch(WagtailTestCase): +class TestPageSearch(TestCase, WagtailTestUtils): def setUp(self): # Login self.login() @@ -396,7 +397,7 @@ def test_root_can_appear_in_search_results(self): self.assertTrue(any([r.slug == 'root' for r in results])) -class TestPageMove(WagtailTestCase): +class TestPageMove(TestCase, WagtailTestUtils): def setUp(self): # Find root page self.root_page = Page.objects.get(id=2) @@ -448,7 +449,7 @@ def test_page_set_page_position(self): self.assertEqual(response.status_code, 200) -class TestPageUnpublish(WagtailTestCase): +class TestPageUnpublish(TestCase, WagtailTestUtils): def setUp(self): self.user = self.login() @@ -516,7 +517,7 @@ def test_unpublish_view_post(self): self.assertFalse(SimplePage.objects.get(id=self.page.id).live) -class TestApproveRejectModeration(WagtailTestCase): +class TestApproveRejectModeration(TestCase, WagtailTestUtils): def setUp(self): self.submitter = User.objects.create_superuser( username='submitter', @@ -654,7 +655,7 @@ def test_preview_for_moderation(self): self.assertContains(response, "Hello world!") -class TestContentTypeUse(WagtailTestCase): +class TestContentTypeUse(TestCase, WagtailTestUtils): fixtures = ['test.json'] def setUp(self): From d9825e9531c3067c3261bdc7ac04042c50e92148 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 2 Jun 2014 14:03:02 +0100 Subject: [PATCH 033/293] Fixed missing import --- wagtail/tests/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/wagtail/tests/utils.py b/wagtail/tests/utils.py index 4b22b000c53..0497b239a92 100644 --- a/wagtail/tests/utils.py +++ b/wagtail/tests/utils.py @@ -1,6 +1,7 @@ from django.test import TestCase from django.contrib.auth.models import User from django.utils.six.moves.urllib.parse import urlparse, ParseResult +from django.http import QueryDict # We need to make sure that we're using the same unittest library that Django uses internally # Otherwise, we get issues with the "SkipTest" and "ExpectedFailure" exceptions being recognised as errors From 106b27a5a5699fe369f841141bbf3cc219da6864 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 2 Jun 2014 15:23:32 +0100 Subject: [PATCH 034/293] Added template used assertions into many tests --- wagtail/wagtailadmin/tests/tests.py | 2 +- wagtail/wagtaildocs/tests.py | 54 ++++++++++++++----- wagtail/wagtailimages/tests.py | 48 ++++++++++++----- wagtail/wagtailredirects/tests.py | 24 ++++++--- .../wagtailsearch/tests/test_editorspicks.py | 24 ++++++--- wagtail/wagtailsearch/tests/test_frontend.py | 12 +++-- wagtail/wagtailsearch/tests/test_queries.py | 7 ++- wagtail/wagtailsnippets/tests.py | 24 ++++++--- wagtail/wagtailusers/tests.py | 18 ++++--- 9 files changed, 148 insertions(+), 65 deletions(-) diff --git a/wagtail/wagtailadmin/tests/tests.py b/wagtail/wagtailadmin/tests/tests.py index 12aa28a0bff..b0c0896e28f 100644 --- a/wagtail/wagtailadmin/tests/tests.py +++ b/wagtail/wagtailadmin/tests/tests.py @@ -12,7 +12,7 @@ def setUp(self): # Login login(self.client) - def test_status_code(self): + def test_simple(self): response = self.client.get(reverse('wagtailadmin_home')) self.assertEqual(response.status_code, 200) diff --git a/wagtail/wagtaildocs/tests.py b/wagtail/wagtaildocs/tests.py index d068f9a272f..33da3e33aa1 100644 --- a/wagtail/wagtaildocs/tests.py +++ b/wagtail/wagtaildocs/tests.py @@ -46,8 +46,10 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtaildocs_index'), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/documents/index.html') def test_search(self): response = self.get({'q': "Hello"}) @@ -74,8 +76,12 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtaildocs_add_document'), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/documents/add.html') + + # TODO: Test posting class TestDocumentEditView(TestCase): @@ -88,8 +94,12 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtaildocs_edit_document', args=(self.document.id,)), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/documents/edit.html') + + # TODO: Test posting class TestDocumentDeleteView(TestCase): @@ -102,8 +112,12 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtaildocs_delete_document', args=(self.document.id,)), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/documents/confirm_delete.html') + + # TODO: Test posting class TestDocumentChooserView(TestCase): @@ -113,8 +127,11 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtaildocs_chooser'), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/chooser/chooser.html') + self.assertTemplateUsed(response, 'wagtaildocs/chooser/chooser.js') def test_search(self): response = self.get({'q': "Hello"}) @@ -138,8 +155,12 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtaildocs_document_chosen', args=(self.document.id,)), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/chooser/document_chosen.js') + + # TODO: Test posting class TestDocumentChooserUploadView(TestCase): @@ -149,8 +170,13 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtaildocs_chooser_upload'), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/chooser/chooser.html') + self.assertTemplateUsed(response, 'wagtaildocs/chooser/chooser.js') + + # TODO: Test document upload with chooser class TestDocumentFilenameProperties(TestCase): diff --git a/wagtail/wagtailimages/tests.py b/wagtail/wagtailimages/tests.py index 00d1245e646..fdadc37041b 100644 --- a/wagtail/wagtailimages/tests.py +++ b/wagtail/wagtailimages/tests.py @@ -194,8 +194,10 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtailimages_index'), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailimages/images/index.html') def test_search(self): response = self.get({'q': "Hello"}) @@ -225,8 +227,10 @@ def get(self, params={}): def post(self, post_data={}): return self.client.post(reverse('wagtailimages_add_image'), post_data) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailimages/images/add.html') def test_add(self): response = self.post({ @@ -263,8 +267,10 @@ def get(self, params={}): def post(self, post_data={}): return self.client.post(reverse('wagtailimages_edit_image', args=(self.image.id,)), post_data) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailimages/images/edit.html') def test_edit(self): response = self.post({ @@ -295,8 +301,10 @@ def get(self, params={}): def post(self, post_data={}): return self.client.post(reverse('wagtailimages_delete_image', args=(self.image.id,)), post_data) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailimages/images/confirm_delete.html') def test_delete(self): response = self.post({ @@ -318,8 +326,11 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtailimages_chooser'), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailimages/chooser/chooser.html') + self.assertTemplateUsed(response, 'wagtailimages/chooser/chooser.js') def test_search(self): response = self.get({'q': "Hello"}) @@ -346,8 +357,12 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtailimages_image_chosen', args=(self.image.id,)), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailimages/chooser/image_chosen.js') + + # TODO: Test posting class TestImageChooserUploadView(TestCase): @@ -357,5 +372,10 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtailimages_chooser_upload'), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailimages/chooser/chooser.html') + self.assertTemplateUsed(response, 'wagtailimages/chooser/chooser.js') + + # TODO: Test uploading through chooser diff --git a/wagtail/wagtailredirects/tests.py b/wagtail/wagtailredirects/tests.py index a14a853fa70..f23ea63c997 100644 --- a/wagtail/wagtailredirects/tests.py +++ b/wagtail/wagtailredirects/tests.py @@ -73,8 +73,10 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtailredirects_index'), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailredirects/index.html') def test_search(self): response = self.get({'q': "Hello"}) @@ -98,8 +100,10 @@ def get(self, params={}): def post(self, post_data={}): return self.client.post(reverse('wagtailredirects_add_redirect'), post_data) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailredirects/add.html') def test_add(self): response = self.post({ @@ -142,8 +146,10 @@ def get(self, params={}, redirect_id=None): def post(self, post_data={}, redirect_id=None): return self.client.post(reverse('wagtailredirects_edit_redirect', args=(redirect_id or self.redirect.id, )), post_data) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailredirects/edit.html') def test_nonexistant_redirect(self): self.assertEqual(self.get(redirect_id=100000).status_code, 404) @@ -188,8 +194,10 @@ def get(self, params={}, redirect_id=None): def post(self, post_data={}, redirect_id=None): return self.client.post(reverse('wagtailredirects_delete_redirect', args=(redirect_id or self.redirect.id, )), post_data) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailredirects/confirm_delete.html') def test_nonexistant_redirect(self): self.assertEqual(self.get(redirect_id=100000).status_code, 404) diff --git a/wagtail/wagtailsearch/tests/test_editorspicks.py b/wagtail/wagtailsearch/tests/test_editorspicks.py index e0b49153fa1..2af0df625b0 100644 --- a/wagtail/wagtailsearch/tests/test_editorspicks.py +++ b/wagtail/wagtailsearch/tests/test_editorspicks.py @@ -52,8 +52,10 @@ def setUp(self): def get(self, params={}): return self.client.get('/admin/search/editorspicks/', params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/index.html') def test_search(self): response = self.get({'q': "Hello"}) @@ -74,8 +76,10 @@ def setUp(self): def get(self, params={}): return self.client.get('/admin/search/editorspicks/add/', params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/add.html') class TestEditorsPicksEditView(TestCase): @@ -89,8 +93,10 @@ def setUp(self): def get(self, params={}): return self.client.get('/admin/search/editorspicks/' + str(self.query.id) + '/', params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/edit.html') class TestEditorsPicksDeleteView(TestCase): @@ -104,5 +110,7 @@ def setUp(self): def get(self, params={}): return self.client.get('/admin/search/editorspicks/' + str(self.query.id) + '/delete/', params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/confirm_delete.html') diff --git a/wagtail/wagtailsearch/tests/test_frontend.py b/wagtail/wagtailsearch/tests/test_frontend.py index 82189cfc9c3..8081c968dbd 100644 --- a/wagtail/wagtailsearch/tests/test_frontend.py +++ b/wagtail/wagtailsearch/tests/test_frontend.py @@ -5,8 +5,10 @@ class TestSearchView(TestCase): def get(self, params={}): return self.client.get('/search/', params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsearch/search_results.html') def test_search(self): response = self.get({'q': "Hello"}) @@ -24,8 +26,10 @@ class TestSuggestionsView(TestCase): def get(self, params={}): return self.client.get('/search/suggest/', params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + # TODO: Check that a valid JSON document was returned def test_search(self): response = self.get({'q': "Hello"}) diff --git a/wagtail/wagtailsearch/tests/test_queries.py b/wagtail/wagtailsearch/tests/test_queries.py index 7086d46f434..67325104d39 100644 --- a/wagtail/wagtailsearch/tests/test_queries.py +++ b/wagtail/wagtailsearch/tests/test_queries.py @@ -146,8 +146,11 @@ def setUp(self): def get(self, params={}): return self.client.get('/admin/search/queries/chooser/', params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsearch/queries/chooser/chooser.html') + self.assertTemplateUsed(response, 'wagtailsearch/queries/chooser/chooser.js') def test_search(self): response = self.get({'q': "Hello"}) diff --git a/wagtail/wagtailsnippets/tests.py b/wagtail/wagtailsnippets/tests.py index fd283f7f550..f68062319ce 100644 --- a/wagtail/wagtailsnippets/tests.py +++ b/wagtail/wagtailsnippets/tests.py @@ -13,8 +13,10 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtailsnippets_index'), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsnippets/snippets/index.html') def test_displays_snippet(self): self.assertContains(self.get(), "Adverts") @@ -29,8 +31,10 @@ def get(self, params={}): args=('tests', 'advert')), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsnippets/snippets/type_index.html') def test_displays_add_button(self): self.assertContains(self.get(), "Add advert") @@ -50,8 +54,10 @@ def post(self, post_data={}): args=('tests', 'advert')), post_data) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsnippets/snippets/create.html') def test_create_invalid(self): response = self.post(post_data={'foo': 'bar'}) @@ -87,8 +93,10 @@ def post(self, post_data={}): args=('tests', 'advert', self.test_snippet.id)), post_data) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsnippets/snippets/edit.html') def test_non_existant_model(self): response = self.client.get(reverse('wagtailsnippets_edit', diff --git a/wagtail/wagtailusers/tests.py b/wagtail/wagtailusers/tests.py index bfe0fe4ef0c..d60d33d4731 100644 --- a/wagtail/wagtailusers/tests.py +++ b/wagtail/wagtailusers/tests.py @@ -11,8 +11,10 @@ def setUp(self): def get(self, params={}): return self.client.get(reverse('wagtailusers_index'), params) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailusers/index.html') def test_search(self): response = self.get({'q': "Hello"}) @@ -36,8 +38,10 @@ def get(self, params={}): def post(self, post_data={}): return self.client.post(reverse('wagtailusers_create'), post_data) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailusers/create.html') def test_create(self): response = self.post({ @@ -72,8 +76,10 @@ def get(self, params={}, user_id=None): def post(self, post_data={}, user_id=None): return self.client.post(reverse('wagtailusers_edit', args=(user_id or self.test_user.id, )), post_data) - def test_status_code(self): - self.assertEqual(self.get().status_code, 200) + def test_simple(self): + response = self.get() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailusers/edit.html') def test_nonexistant_redirect(self): self.assertEqual(self.get(user_id=100000).status_code, 404) From f4ee926ffaa17f318cca5ec226a4685866811be7 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 2 Jun 2014 15:56:03 +0100 Subject: [PATCH 035/293] Added URL assertions to tests which test redirecting --- wagtail/wagtailimages/tests.py | 11 +++++++---- wagtail/wagtailredirects/tests.py | 11 +++++++---- wagtail/wagtailsnippets/tests.py | 11 +++++++---- wagtail/wagtailusers/tests.py | 8 +++++--- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/wagtail/wagtailimages/tests.py b/wagtail/wagtailimages/tests.py index fdadc37041b..c8f0194c0ee 100644 --- a/wagtail/wagtailimages/tests.py +++ b/wagtail/wagtailimages/tests.py @@ -4,7 +4,7 @@ from django.core.urlresolvers import reverse from django.core.files.uploadedfile import SimpleUploadedFile -from wagtail.tests.utils import login, unittest +from wagtail.tests.utils import login, unittest, WagtailTestUtils from wagtail.wagtailimages.models import get_image_model from wagtail.wagtailimages.templatetags import image_tags @@ -217,7 +217,7 @@ def test_ordering(self): self.assertEqual(response.status_code, 200) -class TestImageAddView(TestCase): +class TestImageAddView(TestCase, WagtailTestUtils): def setUp(self): login(self.client) @@ -240,6 +240,7 @@ def test_add(self): # Should redirect back to index self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailimages_index')) # Check that the image was created images = Image.objects.filter(title="Test image") @@ -251,7 +252,7 @@ def test_add(self): self.assertEqual(image.height, 480) -class TestImageEditView(TestCase): +class TestImageEditView(TestCase, WagtailTestUtils): def setUp(self): login(self.client) @@ -279,13 +280,14 @@ def test_edit(self): # Should redirect back to index self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailimages_index')) # Check that the image was edited image = Image.objects.get(id=self.image.id) self.assertEqual(image.title, "Edited") -class TestImageDeleteView(TestCase): +class TestImageDeleteView(TestCase, WagtailTestUtils): def setUp(self): login(self.client) @@ -313,6 +315,7 @@ def test_delete(self): # Should redirect back to index self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailimages_index')) # Check that the image was deleted images = Image.objects.filter(title="Test image") diff --git a/wagtail/wagtailredirects/tests.py b/wagtail/wagtailredirects/tests.py index f23ea63c997..543a8dd7016 100644 --- a/wagtail/wagtailredirects/tests.py +++ b/wagtail/wagtailredirects/tests.py @@ -1,7 +1,7 @@ from django.test import TestCase from django.test.client import Client from wagtail.wagtailredirects import models -from wagtail.tests.utils import login +from wagtail.tests.utils import login, WagtailTestUtils from django.core.urlresolvers import reverse @@ -90,7 +90,7 @@ def test_pagination(self): self.assertEqual(response.status_code, 200) -class TestRedirectsAddView(TestCase): +class TestRedirectsAddView(TestCase, WagtailTestUtils): def setUp(self): login(self.client) @@ -114,6 +114,7 @@ def test_add(self): # Should redirect back to index self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailredirects_index')) # Check that the redirect was created redirects = models.Redirect.objects.filter(old_path='/test') @@ -131,7 +132,7 @@ def test_add_validation_error(self): self.assertEqual(response.status_code, 200) -class TestRedirectsEditView(TestCase): +class TestRedirectsEditView(TestCase, WagtailTestUtils): def setUp(self): # Create a redirect to edit self.redirect = models.Redirect(old_path='/test', redirect_link='http://www.test.com/') @@ -163,6 +164,7 @@ def test_edit(self): # Should redirect back to index self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailredirects_index')) # Check that the redirect was edited redirects = models.Redirect.objects.filter(old_path='/test') @@ -179,7 +181,7 @@ def test_edit_validation_error(self): # Should not redirect to index self.assertEqual(response.status_code, 200) -class TestRedirectsDeleteView(TestCase): +class TestRedirectsDeleteView(TestCase, WagtailTestUtils): def setUp(self): # Create a redirect to edit self.redirect = models.Redirect(old_path='/test', redirect_link='http://www.test.com/') @@ -209,6 +211,7 @@ def test_delete(self): # Should redirect back to index self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailredirects_index')) # Check that the redirect was deleted redirects = models.Redirect.objects.filter(old_path='/test') diff --git a/wagtail/wagtailsnippets/tests.py b/wagtail/wagtailsnippets/tests.py index f68062319ce..3adaf5a3bd3 100644 --- a/wagtail/wagtailsnippets/tests.py +++ b/wagtail/wagtailsnippets/tests.py @@ -2,7 +2,7 @@ from django.core.urlresolvers import reverse from django.contrib.auth.models import User -from wagtail.tests.utils import login, unittest +from wagtail.tests.utils import login, unittest, WagtailTestUtils from wagtail.tests.models import Advert @@ -40,7 +40,7 @@ def test_displays_add_button(self): self.assertContains(self.get(), "Add advert") -class TestSnippetCreateView(TestCase): +class TestSnippetCreateView(TestCase, WagtailTestUtils): def setUp(self): login(self.client) @@ -68,13 +68,14 @@ def test_create(self): response = self.post(post_data={'text': 'test_advert', 'url': 'http://www.example.com/'}) self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailsnippets_list', args=('tests', 'advert'))) snippets = Advert.objects.filter(text='test_advert') self.assertEqual(snippets.count(), 1) self.assertEqual(snippets.first().url, 'http://www.example.com/') -class TestSnippetEditView(TestCase): +class TestSnippetEditView(TestCase, WagtailTestUtils): def setUp(self): self.test_snippet = Advert() self.test_snippet.text = 'test_advert' @@ -117,13 +118,14 @@ def test_edit(self): response = self.post(post_data={'text': 'edited_test_advert', 'url': 'http://www.example.com/edited'}) self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailsnippets_list', args=('tests', 'advert'))) snippets = Advert.objects.filter(text='edited_test_advert') self.assertEqual(snippets.count(), 1) self.assertEqual(snippets.first().url, 'http://www.example.com/edited') -class TestSnippetDelete(TestCase): +class TestSnippetDelete(TestCase, WagtailTestUtils): def setUp(self): self.test_snippet = Advert() self.test_snippet.text = 'test_advert' @@ -142,6 +144,7 @@ def test_delete_post(self): # Should be redirected to explorer page self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailsnippets_list', args=('tests', 'advert'))) # Check that the page is gone self.assertEqual(Advert.objects.filter(text='test_advert').count(), 0) diff --git a/wagtail/wagtailusers/tests.py b/wagtail/wagtailusers/tests.py index d60d33d4731..c9105e3c092 100644 --- a/wagtail/wagtailusers/tests.py +++ b/wagtail/wagtailusers/tests.py @@ -1,7 +1,7 @@ from django.test import TestCase from django.core.urlresolvers import reverse from django.contrib.auth.models import User -from wagtail.tests.utils import login +from wagtail.tests.utils import login, WagtailTestUtils class TestUserIndexView(TestCase): @@ -28,7 +28,7 @@ def test_pagination(self): self.assertEqual(response.status_code, 200) -class TestUserCreateView(TestCase): +class TestUserCreateView(TestCase, WagtailTestUtils): def setUp(self): login(self.client) @@ -55,6 +55,7 @@ def test_create(self): # Should redirect back to index self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailusers_index')) # Check that the user was created users = User.objects.filter(username='testuser') @@ -62,7 +63,7 @@ def test_create(self): self.assertEqual(users.first().email, 'test@user.com') -class TestUserEditView(TestCase): +class TestUserEditView(TestCase, WagtailTestUtils): def setUp(self): # Create a user to edit self.test_user = User.objects.create_user(username='testuser', email='testuser@email.com', password='password') @@ -96,6 +97,7 @@ def test_edit(self): # Should redirect back to index self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailusers_index')) # Check that the user was edited user = User.objects.get(id=self.test_user.id) From eddc3fc917791c80c3bad250721bbb30ace9238e Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 2 Jun 2014 16:07:31 +0100 Subject: [PATCH 036/293] Always use login method from WagtailTestUtils --- wagtail/tests/utils.py | 18 +++++------ wagtail/wagtailadmin/tests/tests.py | 10 +++---- wagtail/wagtaildocs/tests.py | 30 +++++++++---------- wagtail/wagtailembeds/tests.py | 6 ++-- wagtail/wagtailimages/tests.py | 24 +++++++-------- wagtail/wagtailredirects/tests.py | 12 ++++---- .../wagtailsearch/tests/test_editorspicks.py | 24 +++++++++------ wagtail/wagtailsearch/tests/test_queries.py | 6 ++-- wagtail/wagtailsnippets/tests.py | 16 +++++----- wagtail/wagtailusers/tests.py | 10 +++---- 10 files changed, 79 insertions(+), 77 deletions(-) diff --git a/wagtail/tests/utils.py b/wagtail/tests/utils.py index 0497b239a92..0b13e593203 100644 --- a/wagtail/tests/utils.py +++ b/wagtail/tests/utils.py @@ -15,19 +15,15 @@ import unittest -def login(client): - # Create a user - user = User.objects.create_superuser(username='test', email='test@email.com', password='password') - - # Login - client.login(username='test', password='password') - - return user - - class WagtailTestUtils(object): def login(self): - return login(self.client) + # Create a user + user = User.objects.create_superuser(username='test', email='test@email.com', password='password') + + # Login + self.client.login(username='test', password='password') + + return user # From: https://github.com/django/django/blob/255449c1ee61c14778658caae8c430fa4d76afd6/django/contrib/auth/tests/test_views.py#L70-L85 def assertURLEqual(self, url, expected, parse_qs=False): diff --git a/wagtail/wagtailadmin/tests/tests.py b/wagtail/wagtailadmin/tests/tests.py index b0c0896e28f..f014c026df2 100644 --- a/wagtail/wagtailadmin/tests/tests.py +++ b/wagtail/wagtailadmin/tests/tests.py @@ -1,26 +1,26 @@ from django.test import TestCase from wagtail.tests.models import SimplePage, EventPage -from wagtail.tests.utils import login, unittest +from wagtail.tests.utils import unittest, WagtailTestUtils from wagtail.wagtailcore.models import Page from wagtail.wagtailadmin.tasks import send_email_task from django.core.urlresolvers import reverse from django.core import mail -class TestHome(TestCase): +class TestHome(TestCase, WagtailTestUtils): def setUp(self): # Login - login(self.client) + self.login() def test_simple(self): response = self.client.get(reverse('wagtailadmin_home')) self.assertEqual(response.status_code, 200) -class TestEditorHooks(TestCase): +class TestEditorHooks(TestCase, WagtailTestUtils): def setUp(self): self.homepage = Page.objects.get(id=2) - login(self.client) + self.login() def test_editor_css_and_js_hooks_on_add(self): response = self.client.get(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.homepage.id))) diff --git a/wagtail/wagtaildocs/tests.py b/wagtail/wagtaildocs/tests.py index 33da3e33aa1..3353ce39ed9 100644 --- a/wagtail/wagtaildocs/tests.py +++ b/wagtail/wagtaildocs/tests.py @@ -1,6 +1,6 @@ from django.test import TestCase from wagtail.wagtaildocs import models -from wagtail.tests.utils import login +from wagtail.tests.utils import WagtailTestUtils from django.contrib.auth.models import User, Group, Permission from django.core.urlresolvers import reverse from django.core.files.base import ContentFile @@ -39,9 +39,9 @@ def test_user_cant_edit(self): ## ===== ADMIN VIEWS ===== -class TestDocumentIndexView(TestCase): +class TestDocumentIndexView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtaildocs_index'), params) @@ -69,9 +69,9 @@ def test_ordering(self): self.assertEqual(response.status_code, 200) -class TestDocumentAddView(TestCase): +class TestDocumentAddView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtaildocs_add_document'), params) @@ -84,9 +84,9 @@ def test_simple(self): # TODO: Test posting -class TestDocumentEditView(TestCase): +class TestDocumentEditView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() # Create a document to edit self.document = models.Document.objects.create(title="Test document") @@ -102,9 +102,9 @@ def test_simple(self): # TODO: Test posting -class TestDocumentDeleteView(TestCase): +class TestDocumentDeleteView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() # Create a document to delete self.document = models.Document.objects.create(title="Test document") @@ -120,9 +120,9 @@ def test_simple(self): # TODO: Test posting -class TestDocumentChooserView(TestCase): +class TestDocumentChooserView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtaildocs_chooser'), params) @@ -145,9 +145,9 @@ def test_pagination(self): self.assertEqual(response.status_code, 200) -class TestDocumentChooserChosenView(TestCase): +class TestDocumentChooserChosenView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() # Create a document to choose self.document = models.Document.objects.create(title="Test document") @@ -163,9 +163,9 @@ def test_simple(self): # TODO: Test posting -class TestDocumentChooserUploadView(TestCase): +class TestDocumentChooserUploadView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtaildocs_chooser_upload'), params) diff --git a/wagtail/wagtailembeds/tests.py b/wagtail/wagtailembeds/tests.py index b1eefdb1787..b1268729e28 100644 --- a/wagtail/wagtailembeds/tests.py +++ b/wagtail/wagtailembeds/tests.py @@ -1,7 +1,7 @@ from django.test import TestCase from django.test.client import Client -from wagtail.tests.utils import login from wagtail.wagtailembeds import get_embed +from wagtail.tests.utils import WagtailTestUtils class TestEmbeds(TestCase): @@ -63,10 +63,10 @@ def test_invalid_width(self): self.assertEqual(embed.width, None) -class TestChooser(TestCase): +class TestChooser(TestCase, WagtailTestUtils): def setUp(self): # login - login(self.client) + self.login() def test_chooser(self): r = self.client.get('/admin/embeds/chooser/') diff --git a/wagtail/wagtailimages/tests.py b/wagtail/wagtailimages/tests.py index c8f0194c0ee..d01535edacb 100644 --- a/wagtail/wagtailimages/tests.py +++ b/wagtail/wagtailimages/tests.py @@ -4,7 +4,7 @@ from django.core.urlresolvers import reverse from django.core.files.uploadedfile import SimpleUploadedFile -from wagtail.tests.utils import login, unittest, WagtailTestUtils +from wagtail.tests.utils import unittest, WagtailTestUtils from wagtail.wagtailimages.models import get_image_model from wagtail.wagtailimages.templatetags import image_tags @@ -187,9 +187,9 @@ def test_image_tag(self): ## ===== ADMIN VIEWS ===== -class TestImageIndexView(TestCase): +class TestImageIndexView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailimages_index'), params) @@ -219,7 +219,7 @@ def test_ordering(self): class TestImageAddView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailimages_add_image'), params) @@ -254,7 +254,7 @@ def test_add(self): class TestImageEditView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() # Create an image to edit self.image = Image.objects.create( @@ -289,7 +289,7 @@ def test_edit(self): class TestImageDeleteView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() # Create an image to edit self.image = Image.objects.create( @@ -322,9 +322,9 @@ def test_delete(self): self.assertEqual(images.count(), 0) -class TestImageChooserView(TestCase): +class TestImageChooserView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailimages_chooser'), params) @@ -347,9 +347,9 @@ def test_pagination(self): self.assertEqual(response.status_code, 200) -class TestImageChooserChosenView(TestCase): +class TestImageChooserChosenView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() # Create an image to edit self.image = Image.objects.create( @@ -368,9 +368,9 @@ def test_simple(self): # TODO: Test posting -class TestImageChooserUploadView(TestCase): +class TestImageChooserUploadView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailimages_chooser_upload'), params) diff --git a/wagtail/wagtailredirects/tests.py b/wagtail/wagtailredirects/tests.py index 543a8dd7016..29ad7ec0bd2 100644 --- a/wagtail/wagtailredirects/tests.py +++ b/wagtail/wagtailredirects/tests.py @@ -1,7 +1,7 @@ from django.test import TestCase from django.test.client import Client from wagtail.wagtailredirects import models -from wagtail.tests.utils import login, WagtailTestUtils +from wagtail.tests.utils import WagtailTestUtils from django.core.urlresolvers import reverse @@ -66,9 +66,9 @@ def test_temporary_redirect(self): self.assertTrue(r.has_header('Location')) -class TestRedirectsIndexView(TestCase): +class TestRedirectsIndexView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailredirects_index'), params) @@ -92,7 +92,7 @@ def test_pagination(self): class TestRedirectsAddView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailredirects_add_redirect'), params) @@ -139,7 +139,7 @@ def setUp(self): self.redirect.save() # Login - login(self.client) + self.login() def get(self, params={}, redirect_id=None): return self.client.get(reverse('wagtailredirects_edit_redirect', args=(redirect_id or self.redirect.id, )), params) @@ -188,7 +188,7 @@ def setUp(self): self.redirect.save() # Login - login(self.client) + self.login() def get(self, params={}, redirect_id=None): return self.client.get(reverse('wagtailredirects_delete_redirect', args=(redirect_id or self.redirect.id, )), params) diff --git a/wagtail/wagtailsearch/tests/test_editorspicks.py b/wagtail/wagtailsearch/tests/test_editorspicks.py index 2af0df625b0..7ee974fd0d3 100644 --- a/wagtail/wagtailsearch/tests/test_editorspicks.py +++ b/wagtail/wagtailsearch/tests/test_editorspicks.py @@ -1,5 +1,5 @@ from django.test import TestCase -from wagtail.tests.utils import login +from wagtail.tests.utils import unittest, WagtailTestUtils from wagtail.wagtailsearch import models @@ -45,9 +45,9 @@ def test_editors_pick_ordering(self): self.assertEqual(models.Query.get("root page").editors_picks.last().description, "Last editors pick") -class TestEditorsPicksIndexView(TestCase): +class TestEditorsPicksIndexView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get('/admin/search/editorspicks/', params) @@ -69,9 +69,9 @@ def test_pagination(self): self.assertEqual(response.status_code, 200) -class TestEditorsPicksAddView(TestCase): +class TestEditorsPicksAddView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get('/admin/search/editorspicks/add/', params) @@ -81,10 +81,12 @@ def test_simple(self): self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/add.html') + # TODO: Test posting -class TestEditorsPicksEditView(TestCase): + +class TestEditorsPicksEditView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() # Create an editors pick to edit self.query = models.Query.get("Hello") @@ -98,10 +100,12 @@ def test_simple(self): self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/edit.html') + # TODO: Test posting + -class TestEditorsPicksDeleteView(TestCase): +class TestEditorsPicksDeleteView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() # Create an editors pick to delete self.query = models.Query.get("Hello") @@ -114,3 +118,5 @@ def test_simple(self): response = self.get() self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/confirm_delete.html') + + # TODO: Test posting diff --git a/wagtail/wagtailsearch/tests/test_queries.py b/wagtail/wagtailsearch/tests/test_queries.py index 67325104d39..ee5382db426 100644 --- a/wagtail/wagtailsearch/tests/test_queries.py +++ b/wagtail/wagtailsearch/tests/test_queries.py @@ -1,7 +1,7 @@ from django.test import TestCase from django.core import management from wagtail.wagtailsearch import models -from wagtail.tests.utils import login, unittest +from wagtail.tests.utils import unittest, WagtailTestUtils from StringIO import StringIO @@ -139,9 +139,9 @@ def test_garbage_collect_command(self): # TODO: Test that this command is acctually doing its job -class TestQueryChooserView(TestCase): +class TestQueryChooserView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get('/admin/search/queries/chooser/', params) diff --git a/wagtail/wagtailsnippets/tests.py b/wagtail/wagtailsnippets/tests.py index 3adaf5a3bd3..bf9d6273169 100644 --- a/wagtail/wagtailsnippets/tests.py +++ b/wagtail/wagtailsnippets/tests.py @@ -2,13 +2,13 @@ from django.core.urlresolvers import reverse from django.contrib.auth.models import User -from wagtail.tests.utils import login, unittest, WagtailTestUtils +from wagtail.tests.utils import unittest, WagtailTestUtils from wagtail.tests.models import Advert -class TestSnippetIndexView(TestCase): +class TestSnippetIndexView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailsnippets_index'), params) @@ -22,9 +22,9 @@ def test_displays_snippet(self): self.assertContains(self.get(), "Adverts") -class TestSnippetListView(TestCase): +class TestSnippetListView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailsnippets_list', @@ -42,7 +42,7 @@ def test_displays_add_button(self): class TestSnippetCreateView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailsnippets_create', @@ -82,7 +82,7 @@ def setUp(self): self.test_snippet.url = 'http://www.example.com/' self.test_snippet.save() - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailsnippets_edit', @@ -132,7 +132,7 @@ def setUp(self): self.test_snippet.url = 'http://www.example.com/' self.test_snippet.save() - login(self.client) + self.login() def test_delete_get(self): response = self.client.get(reverse('wagtailsnippets_delete', args=('tests', 'advert', self.test_snippet.id, ))) diff --git a/wagtail/wagtailusers/tests.py b/wagtail/wagtailusers/tests.py index c9105e3c092..6de97f202ec 100644 --- a/wagtail/wagtailusers/tests.py +++ b/wagtail/wagtailusers/tests.py @@ -1,12 +1,12 @@ from django.test import TestCase from django.core.urlresolvers import reverse from django.contrib.auth.models import User -from wagtail.tests.utils import login, WagtailTestUtils +from wagtail.tests.utils import WagtailTestUtils -class TestUserIndexView(TestCase): +class TestUserIndexView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailusers_index'), params) @@ -30,7 +30,7 @@ def test_pagination(self): class TestUserCreateView(TestCase, WagtailTestUtils): def setUp(self): - login(self.client) + self.login() def get(self, params={}): return self.client.get(reverse('wagtailusers_create'), params) @@ -69,7 +69,7 @@ def setUp(self): self.test_user = User.objects.create_user(username='testuser', email='testuser@email.com', password='password') # Login - login(self.client) + self.login() def get(self, params={}, user_id=None): return self.client.get(reverse('wagtailusers_edit', args=(user_id or self.test_user.id, )), params) From 3fa98ef82ed60a622943e54994b819da21841fee Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 10:21:21 +0100 Subject: [PATCH 037/293] Renamed scheduled publishing fields --- wagtail/wagtailadmin/tests.py | 120 +++++++++--------- wagtail/wagtailadmin/views/pages.py | 34 ++--- .../commands/publish_scheduled_pages.py | 16 +-- .../0003_fields_for_scheduled_publishing.py | 30 ++--- wagtail/wagtailcore/models.py | 32 ++--- 5 files changed, 116 insertions(+), 116 deletions(-) diff --git a/wagtail/wagtailadmin/tests.py b/wagtail/wagtailadmin/tests.py index 3bddc864c3e..4d6016609f4 100644 --- a/wagtail/wagtailadmin/tests.py +++ b/wagtail/wagtailadmin/tests.py @@ -78,14 +78,14 @@ def test_create_simplepage_post(self): self.assertFalse(page.live) def test_create_simplepage_scheduled(self): - go_live_datetime = timezone.now() + timedelta(days=1) - expiry_datetime = timezone.now() + timedelta(days=2) + go_live_at = timezone.now() + timedelta(days=1) + expire_at = timezone.now() + timedelta(days=2) post_data = { 'title': "New page!", 'content': "Some content", 'slug': 'hello-world', - 'go_live_datetime': str(go_live_datetime).split('.')[0], - 'expiry_datetime': str(expiry_datetime).split('.')[0], + 'go_live_at': str(go_live_at).split('.')[0], + 'expire_at': str(expire_at).split('.')[0], } response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data) @@ -94,21 +94,21 @@ def test_create_simplepage_scheduled(self): # Find the page and check the scheduled times page = Page.objects.get(path__startswith=self.root_page.path, slug='hello-world').specific - self.assertEquals(page.go_live_datetime.date(), go_live_datetime.date()) - self.assertEquals(page.expiry_datetime.date(), expiry_datetime.date()) + self.assertEquals(page.go_live_at.date(), go_live_at.date()) + self.assertEquals(page.expire_at.date(), expire_at.date()) self.assertEquals(page.expired, False) self.assertTrue(page.status_string, "draft") - # No revisions with approved_go_live_datetime - self.assertFalse(PageRevision.objects.filter(page=page).exclude(approved_go_live_datetime__isnull=True).exists()) + # No revisions with approved_go_live_at + self.assertFalse(PageRevision.objects.filter(page=page).exclude(approved_go_live_at__isnull=True).exists()) def test_create_simplepage_scheduled_go_live_before_expiry(self): post_data = { 'title': "New page!", 'content': "Some content", 'slug': 'hello-world', - 'go_live_datetime': str(timezone.now() + timedelta(days=2)).split('.')[0], - 'expiry_datetime': str(timezone.now() + timedelta(days=1)).split('.')[0], + 'go_live_at': str(timezone.now() + timedelta(days=2)).split('.')[0], + 'expire_at': str(timezone.now() + timedelta(days=1)).split('.')[0], } response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data) @@ -121,7 +121,7 @@ def test_create_simplepage_scheduled_expire_in_the_past(self): 'title': "New page!", 'content': "Some content", 'slug': 'hello-world', - 'expiry_datetime': str(timezone.now() + timedelta(days=-1)).split('.')[0], + 'expire_at': str(timezone.now() + timedelta(days=-1)).split('.')[0], } response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data) @@ -148,15 +148,15 @@ def test_create_simplepage_post_publish(self): self.assertTrue(page.live) def test_create_simplepage_post_publish_scheduled(self): - go_live_datetime = timezone.now() + timedelta(days=1) - expiry_datetime = timezone.now() + timedelta(days=2) + go_live_at = timezone.now() + timedelta(days=1) + expire_at = timezone.now() + timedelta(days=2) post_data = { 'title': "New page!", 'content': "Some content", 'slug': 'hello-world', 'action-publish': "Publish", - 'go_live_datetime': str(go_live_datetime).split('.')[0], - 'expiry_datetime': str(expiry_datetime).split('.')[0], + 'go_live_at': str(go_live_at).split('.')[0], + 'expire_at': str(expire_at).split('.')[0], } response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'simplepage', self.root_page.id)), post_data) @@ -165,12 +165,12 @@ def test_create_simplepage_post_publish_scheduled(self): # Find the page and check it page = Page.objects.get(path__startswith=self.root_page.path, slug='hello-world').specific - self.assertEquals(page.go_live_datetime.date(), go_live_datetime.date()) - self.assertEquals(page.expiry_datetime.date(), expiry_datetime.date()) + self.assertEquals(page.go_live_at.date(), go_live_at.date()) + self.assertEquals(page.expire_at.date(), expire_at.date()) self.assertEquals(page.expired, False) - # A revision with approved_go_live_datetime should exist now - self.assertTrue(PageRevision.objects.filter(page=page).exclude(approved_go_live_datetime__isnull=True).exists()) + # A revision with approved_go_live_at should exist now + self.assertTrue(PageRevision.objects.filter(page=page).exclude(approved_go_live_at__isnull=True).exists()) # But Page won't be live self.assertFalse(page.live) self.assertTrue(page.status_string, "scheduled") @@ -250,14 +250,14 @@ def test_edit_post(self): self.assertTrue(child_page_new.has_unpublished_changes) def test_edit_post_scheduled(self): - go_live_datetime = timezone.now() + timedelta(days=1) - expiry_datetime = timezone.now() + timedelta(days=2) + go_live_at = timezone.now() + timedelta(days=1) + expire_at = timezone.now() + timedelta(days=2) post_data = { 'title': "I've been edited!", 'content': "Some content", 'slug': 'hello-world', - 'go_live_datetime': str(go_live_datetime).split('.')[0], - 'expiry_datetime': str(expiry_datetime).split('.')[0], + 'go_live_at': str(go_live_at).split('.')[0], + 'expire_at': str(expire_at).split('.')[0], } response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data) @@ -268,11 +268,11 @@ def test_edit_post_scheduled(self): # The page will still be live self.assertTrue(child_page_new.live) - # A revision with approved_go_live_datetime should not exist - self.assertFalse(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_datetime__isnull=True).exists()) - # But a revision with go_live_datetime and expiry_datetime in their content json *should* exist - self.assertTrue(PageRevision.objects.filter(page=child_page_new, content_json__contains=str(go_live_datetime.date())).exists()) - self.assertTrue(PageRevision.objects.filter(page=child_page_new, content_json__contains=str(expiry_datetime.date())).exists()) + # A revision with approved_go_live_at should not exist + self.assertFalse(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_at__isnull=True).exists()) + # But a revision with go_live_at and expire_at in their content json *should* exist + self.assertTrue(PageRevision.objects.filter(page=child_page_new, content_json__contains=str(go_live_at.date())).exists()) + self.assertTrue(PageRevision.objects.filter(page=child_page_new, content_json__contains=str(expire_at.date())).exists()) def test_edit_post_publish(self): # Tests publish from edit page @@ -295,15 +295,15 @@ def test_edit_post_publish(self): self.assertFalse(child_page_new.has_unpublished_changes) def test_edit_post_publish_scheduled(self): - go_live_datetime = timezone.now() + timedelta(days=1) - expiry_datetime = timezone.now() + timedelta(days=2) + go_live_at = timezone.now() + timedelta(days=1) + expire_at = timezone.now() + timedelta(days=2) post_data = { 'title': "I've been edited!", 'content': "Some content", 'slug': 'hello-world', 'action-publish': "Publish", - 'go_live_datetime': str(go_live_datetime).split('.')[0], - 'expiry_datetime': str(expiry_datetime).split('.')[0], + 'go_live_at': str(go_live_at).split('.')[0], + 'expire_at': str(expire_at).split('.')[0], } response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data) @@ -313,20 +313,20 @@ def test_edit_post_publish_scheduled(self): child_page_new = SimplePage.objects.get(id=self.child_page.id) # The page should not be live anymore self.assertFalse(child_page_new.live) - # Instead a revision with approved_go_live_datetime should now exist - self.assertTrue(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_datetime__isnull=True).exists()) + # Instead a revision with approved_go_live_at should now exist + self.assertTrue(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_at__isnull=True).exists()) def test_edit_post_publish_now_an_already_scheduled(self): - # First let's publish a page with a go_live_datetime in the future - go_live_datetime = timezone.now() + timedelta(days=1) - expiry_datetime = timezone.now() + timedelta(days=2) + # First let's publish a page with a go_live_at in the future + go_live_at = timezone.now() + timedelta(days=1) + expire_at = timezone.now() + timedelta(days=2) post_data = { 'title': "I've been edited!", 'content': "Some content", 'slug': 'hello-world', 'action-publish': "Publish", - 'go_live_datetime': str(go_live_datetime).split('.')[0], - 'expiry_datetime': str(expiry_datetime).split('.')[0], + 'go_live_at': str(go_live_at).split('.')[0], + 'expire_at': str(expire_at).split('.')[0], } response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data) @@ -336,17 +336,17 @@ def test_edit_post_publish_now_an_already_scheduled(self): child_page_new = SimplePage.objects.get(id=self.child_page.id) # The page should not be live anymore self.assertFalse(child_page_new.live) - # Instead a revision with approved_go_live_datetime should now exist - self.assertTrue(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_datetime__isnull=True).exists()) + # Instead a revision with approved_go_live_at should now exist + self.assertTrue(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_at__isnull=True).exists()) # Now, let's edit it and publish it right now - go_live_datetime = timezone.now() + go_live_at = timezone.now() post_data = { 'title': "I've been edited!", 'content': "Some content", 'slug': 'hello-world', 'action-publish': "Publish", - 'go_live_datetime': "", + 'go_live_at': "", } response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.child_page.id, )), post_data) @@ -356,8 +356,8 @@ def test_edit_post_publish_now_an_already_scheduled(self): child_page_new = SimplePage.objects.get(id=self.child_page.id) # The page should be live now self.assertTrue(child_page_new.live) - # And a revision with approved_go_live_datetime should not exist - self.assertFalse(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_datetime__isnull=True).exists()) + # And a revision with approved_go_live_at should not exist + self.assertFalse(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_at__isnull=True).exists()) class TestPageDelete(TestCase): def setUp(self): @@ -483,60 +483,60 @@ def test_go_live_page_will_be_published(self): page.title = "Hello world!" page.slug = "hello-world" page.live = False - page.go_live_datetime = timezone.now() - timedelta(days=1) + page.go_live_at = timezone.now() - timedelta(days=1) self.root_page.add_child(instance=page) page.save_revision( - approved_go_live_datetime = timezone.now() - timedelta(days=1) + approved_go_live_at = timezone.now() - timedelta(days=1) ) p = Page.objects.get(slug='hello-world') self.assertFalse(p.live) - self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) management.call_command('publish_scheduled_pages', verbosity=3, interactive=False) #management.call_command('publish_scheduled_pages', dryrun=True, verbosity=3, interactive=False) p = Page.objects.get(slug='hello-world') self.assertTrue(p.live) - self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) def test_go_live_page_will_be_published(self): page = SimplePage() page.title = "Hello world!" page.slug = "hello-world" page.live = False - page.go_live_datetime = timezone.now() - timedelta(days=1) + page.go_live_at = timezone.now() - timedelta(days=1) self.root_page.add_child(instance=page) - page.save_revision(approved_go_live_datetime = timezone.now() - timedelta(days=1)) + page.save_revision(approved_go_live_at = timezone.now() - timedelta(days=1)) p = Page.objects.get(slug='hello-world') self.assertFalse(p.live) - self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) management.call_command('publish_scheduled_pages', ) p = Page.objects.get(slug='hello-world') self.assertTrue(p.live) - self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) def test_future_go_live_page_will_not_be_published(self): page = SimplePage() page.title = "Hello world!" page.slug = "hello-world" page.live = False - page.go_live_datetime = timezone.now() + timedelta(days=1) + page.go_live_at = timezone.now() + timedelta(days=1) self.root_page.add_child(instance=page) - page.save_revision(approved_go_live_datetime = timezone.now() - timedelta(days=1)) + page.save_revision(approved_go_live_at = timezone.now() - timedelta(days=1)) p = Page.objects.get(slug='hello-world') self.assertFalse(p.live) - self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) management.call_command('publish_scheduled_pages', ) p = Page.objects.get(slug='hello-world') self.assertFalse(p.live) - self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_datetime__isnull=True).exists()) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) def test_expired_page_will_be_unpublished(self): page = SimplePage() page.title = "Hello world!" page.slug = "hello-world" page.live = True - page.expiry_datetime = timezone.now() - timedelta(days=1) + page.expire_at = timezone.now() - timedelta(days=1) self.root_page.add_child(instance=page) p = Page.objects.get(slug='hello-world') self.assertTrue(p.live) @@ -550,7 +550,7 @@ def test_future_expired_page_will_not_be_unpublished(self): page.title = "Hello world!" page.slug = "hello-world" page.live = True - page.expiry_datetime = timezone.now() + timedelta(days=1) + page.expire_at = timezone.now() + timedelta(days=1) self.root_page.add_child(instance=page) p = Page.objects.get(slug='hello-world') self.assertTrue(p.live) @@ -564,7 +564,7 @@ def test_expired_pages_are_dropped_from_mod_queue(self): page.title = "Hello world!" page.slug = "hello-world" page.live = False - page.expiry_datetime = timezone.now() - timedelta(days=1) + page.expire_at = timezone.now() - timedelta(days=1) self.root_page.add_child(instance=page) page.save_revision(submitted_for_moderation = True) p = Page.objects.get(slug='hello-world') diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index 26ab715ec54..f4ea960ffc8 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -133,18 +133,18 @@ def clean_slug(slug): is_publishing = bool(request.POST.get('action-publish')) and parent_page_perms.can_publish_subpage() is_submitting = bool(request.POST.get('action-submit')) - go_live_datetime = form.cleaned_data.get('go_live_datetime') - future_go_live = go_live_datetime and go_live_datetime > timezone.now() - approved_go_live_datetime = None + go_live_at = form.cleaned_data.get('go_live_at') + future_go_live = go_live_at and go_live_at > timezone.now() + approved_go_live_at = None if is_publishing: page.has_unpublished_changes = False page.expired = False if future_go_live: page.live = False - # Set approved_go_live_datetime only if is publishing + # Set approved_go_live_at only if is publishing # and the future_go_live is actually in future - approved_go_live_datetime = go_live_datetime + approved_go_live_at = go_live_at else: page.live = True else: @@ -153,11 +153,11 @@ def clean_slug(slug): parent_page.add_child(instance=page) # assign tree parameters - will cause page to be saved - # Pass approved_go_live_datetime to save_revision + # Pass approved_go_live_at to save_revision page.save_revision( user=request.user, submitted_for_moderation=is_submitting, - approved_go_live_datetime = approved_go_live_datetime + approved_go_live_at = approved_go_live_at ) if is_publishing: @@ -222,24 +222,24 @@ def clean_slug(slug): if form.is_valid(): is_publishing = bool(request.POST.get('action-publish')) and page_perms.can_publish() is_submitting = bool(request.POST.get('action-submit')) - go_live_datetime = form.cleaned_data.get('go_live_datetime') - future_go_live = go_live_datetime and go_live_datetime > timezone.now() - approved_go_live_datetime = None + go_live_at = form.cleaned_data.get('go_live_at') + future_go_live = go_live_at and go_live_at > timezone.now() + approved_go_live_at = None if is_publishing: page.has_unpublished_changes = False page.expired = False if future_go_live: page.live = False - # Set approved_go_live_datetime only if publishing - approved_go_live_datetime = go_live_datetime + # Set approved_go_live_at only if publishing + approved_go_live_at = go_live_at else: page.live = True form.save() - # Clear approved_go_live_datetime for older revisions + # Clear approved_go_live_at for older revisions page.revisions.update( submitted_for_moderation=False, - approved_go_live_datetime=None, + approved_go_live_at=None, ) else: # not publishing the page @@ -255,7 +255,7 @@ def clean_slug(slug): page.save_revision( user=request.user, submitted_for_moderation=is_submitting, - approved_go_live_datetime = approved_go_live_datetime + approved_go_live_at = approved_go_live_at ) if is_publishing: @@ -455,8 +455,8 @@ def unpublish(request, page_id): parent_id = page.get_parent().id page.live = False page.save() - # Since page is unpublished clear the approved_go_live_datetime of all revisions - page.revisions.update(approved_go_live_datetime=None) + # Since page is unpublished clear the approved_go_live_at of all revisions + page.revisions.update(approved_go_live_at=None) messages.success(request, _("Page '{0}' unpublished.").format(page.title)) return redirect('wagtailadmin_explore', parent_id) diff --git a/wagtail/wagtailcore/management/commands/publish_scheduled_pages.py b/wagtail/wagtailcore/management/commands/publish_scheduled_pages.py index 0abf3c744e5..b80ace72811 100644 --- a/wagtail/wagtailcore/management/commands/publish_scheduled_pages.py +++ b/wagtail/wagtailcore/management/commands/publish_scheduled_pages.py @@ -8,11 +8,11 @@ def revision_date_expired(r): - expiry_str = json.loads(r.content_json).get('expiry_datetime') + expiry_str = json.loads(r.content_json).get('expire_at') if not expiry_str: return False - expiry_datetime = dateparse.parse_datetime(expiry_str) - if expiry_datetime < timezone.now(): + expire_at = dateparse.parse_datetime(expiry_str) + if expire_at < timezone.now(): return True else: return False @@ -37,7 +37,7 @@ def handle(self, *args, **options): # 1. get all expired pages with live = True expired_pages = Page.objects.filter( live=True, - expiry_datetime__lt=timezone.now() + expire_at__lt=timezone.now() ) if dryrun: if expired_pages: @@ -46,7 +46,7 @@ def handle(self, *args, **options): print "---------------\t\t----\t\t----" for ep in expired_pages: print "{0}\t{1}\t{2}".format( - ep.expiry_datetime.strftime("%Y-%m-%d %H:%M"), + ep.expire_at.strftime("%Y-%m-%d %H:%M"), ep.slug, ep.title ) @@ -71,7 +71,7 @@ def handle(self, *args, **options): rev_data = json.loads(er.content_json) print "{0}\t{1}\t{2}".format( dateparse.parse_datetime( - rev_data.get('expiry_datetime') + rev_data.get('expire_at') ).strftime("%Y-%m-%d %H:%M"), rev_data.get('slug'), rev_data.get('title') @@ -85,7 +85,7 @@ def handle(self, *args, **options): # 3. get all revisions that need to be published revs_for_publishing = PageRevision.objects.filter( - approved_go_live_datetime__lt=timezone.now() + approved_go_live_at__lt=timezone.now() ) if dryrun: print "---------------------------------" @@ -96,7 +96,7 @@ def handle(self, *args, **options): for rp in revs_for_publishing: rev_data = json.loads(rp.content_json) print "{0}\t\t{1}\t{2}".format( - rp.approved_go_live_datetime.strftime("%Y-%m-%d %H:%M"), + rp.approved_go_live_at.strftime("%Y-%m-%d %H:%M"), rev_data.get('slug'), rev_data.get('title') ) diff --git a/wagtail/wagtailcore/migrations/0003_fields_for_scheduled_publishing.py b/wagtail/wagtailcore/migrations/0003_fields_for_scheduled_publishing.py index 5e682aa596b..639068c2b75 100644 --- a/wagtail/wagtailcore/migrations/0003_fields_for_scheduled_publishing.py +++ b/wagtail/wagtailcore/migrations/0003_fields_for_scheduled_publishing.py @@ -8,18 +8,18 @@ class Migration(SchemaMigration): def forwards(self, orm): - # Adding field 'PageRevision.approved_go_live_datetime' - db.add_column(u'wagtailcore_pagerevision', 'approved_go_live_datetime', + # Adding field 'PageRevision.approved_go_live_at' + db.add_column(u'wagtailcore_pagerevision', 'approved_go_live_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False) - # Adding field 'Page.go_live_datetime' - db.add_column(u'wagtailcore_page', 'go_live_datetime', + # Adding field 'Page.go_live_at' + db.add_column(u'wagtailcore_page', 'go_live_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False) - # Adding field 'Page.expiry_datetime' - db.add_column(u'wagtailcore_page', 'expiry_datetime', + # Adding field 'Page.expire_at' + db.add_column(u'wagtailcore_page', 'expire_at', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True), keep_default=False) @@ -30,14 +30,14 @@ def forwards(self, orm): def backwards(self, orm): - # Deleting field 'PageRevision.approved_go_live_datetime' - db.delete_column(u'wagtailcore_pagerevision', 'approved_go_live_datetime') + # Deleting field 'PageRevision.approved_go_live_at' + db.delete_column(u'wagtailcore_pagerevision', 'approved_go_live_at') - # Deleting field 'Page.go_live_datetime' - db.delete_column(u'wagtailcore_page', 'go_live_datetime') + # Deleting field 'Page.go_live_at' + db.delete_column(u'wagtailcore_page', 'go_live_at') - # Deleting field 'Page.expiry_datetime' - db.delete_column(u'wagtailcore_page', 'expiry_datetime') + # Deleting field 'Page.expire_at' + db.delete_column(u'wagtailcore_page', 'expire_at') # Deleting field 'Page.expired' db.delete_column(u'wagtailcore_page', 'expired') @@ -92,8 +92,8 @@ def backwards(self, orm): 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pages'", 'to': u"orm['contenttypes.ContentType']"}), 'depth': ('django.db.models.fields.PositiveIntegerField', [], {}), 'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'expiry_datetime': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'go_live_datetime': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'expire_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'go_live_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), 'has_unpublished_changes': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'live': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), @@ -109,7 +109,7 @@ def backwards(self, orm): }, u'wagtailcore.pagerevision': { 'Meta': {'object_name': 'PageRevision'}, - 'approved_go_live_datetime': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'approved_go_live_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), 'content_json': ('django.db.models.fields.TextField', [], {}), 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index 434b174b646..3b2b055bd1c 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -235,8 +235,8 @@ class Page(MP_Node, ClusterableModel, Indexed): show_in_menus = models.BooleanField(default=False, help_text=_("Whether a link to this page will appear in automatically generated menus")) search_description = models.TextField(blank=True) - go_live_datetime = models.DateTimeField(verbose_name=_("Go live date/time"), help_text=_("Please add a date-time in the form YYYY-MM-DD hh:mm."), blank=True, null=True) - expiry_datetime = models.DateTimeField(verbose_name=_("Expiry date/time"), help_text=_("Please add a date-time in the form YYYY-MM-DD hh:mm."), blank=True, null=True) + go_live_at = models.DateTimeField(verbose_name=_("Go live date/time"), help_text=_("Please add a date-time in the form YYYY-MM-DD hh:mm."), blank=True, null=True) + expire_at = models.DateTimeField(verbose_name=_("Expiry date/time"), help_text=_("Please add a date-time in the form YYYY-MM-DD hh:mm."), blank=True, null=True) expired = models.BooleanField(default=False, editable=False) indexed_fields = { @@ -382,12 +382,12 @@ def route(self, request, path_components): else: raise Http404 - def save_revision(self, user=None, submitted_for_moderation=False, approved_go_live_datetime=None): + def save_revision(self, user=None, submitted_for_moderation=False, approved_go_live_at=None): self.revisions.create( content_json=self.to_json(), user=user, submitted_for_moderation=submitted_for_moderation, - approved_go_live_datetime=approved_go_live_datetime, + approved_go_live_at=approved_go_live_at, ) def get_latest_revision(self): @@ -472,11 +472,11 @@ def relative_url(self, current_site): def clean(self): super(Page, self).clean() - if self.go_live_datetime and self.expiry_datetime: - if self.go_live_datetime > self.expiry_datetime: + if self.go_live_at and self.expire_at: + if self.go_live_at > self.expire_at: raise ValidationError(ugettext('Go live date/time should be before expiry datetime.')) - if self.expiry_datetime and self.expiry_datetime < timezone.now(): + if self.expire_at and self.expire_at < timezone.now(): raise ValidationError(ugettext('Expiry date/time should be in the future')) @classmethod @@ -567,7 +567,7 @@ def status_string(self): @property def approved_schedule(self): - return self.revisions.exclude(approved_go_live_datetime__isnull=True).exists() + return self.revisions.exclude(approved_go_live_at__isnull=True).exists() def has_unpublished_subtree(self): """ @@ -742,7 +742,7 @@ class PageRevision(models.Model): created_at = models.DateTimeField(auto_now_add=True) user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True) content_json = models.TextField() - approved_go_live_datetime = models.DateTimeField(null=True, blank=True) + approved_go_live_at = models.DateTimeField(null=True, blank=True) objects = models.Manager() submitted_revisions = SubmittedRevisionsManager() @@ -776,18 +776,18 @@ def as_page_object(self): def publish(self): page = self.as_page_object() - if page.go_live_datetime and page.go_live_datetime > timezone.now(): + if page.go_live_at and page.go_live_at > timezone.now(): # if we have a go_live in the future don't make the page live page.live = False - # Instead set the approved_go_live_datetime of this revision - self.approved_go_live_datetime = page.go_live_datetime + # Instead set the approved_go_live_at of this revision + self.approved_go_live_at = page.go_live_at self.save() - # And clear the the approved_go_live_datetime of any other revisions - page.revisions.exclude(id=self.id).update(approved_go_live_datetime=None) + # And clear the the approved_go_live_at of any other revisions + page.revisions.exclude(id=self.id).update(approved_go_live_at=None) else: page.live = True - # If page goes live clear the approved_go_live_datetime of all revisions - page.revisions.update(approved_go_live_datetime=None) + # If page goes live clear the approved_go_live_at of all revisions + page.revisions.update(approved_go_live_at=None) page.expired = False # When a page is published it can't be expired page.save() self.submitted_for_moderation = False From ad3c62fed520b086ffd6ccf97779bd29af0cbff2 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 10:22:14 +0100 Subject: [PATCH 038/293] Added go_live_at and expire_at to common page configuration --- wagtail/wagtailadmin/edit_handlers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wagtail/wagtailadmin/edit_handlers.py b/wagtail/wagtailadmin/edit_handlers.py index 370f2f5bbdf..097b5bb2105 100644 --- a/wagtail/wagtailadmin/edit_handlers.py +++ b/wagtail/wagtailadmin/edit_handlers.py @@ -731,5 +731,7 @@ def InlinePanel(base_model, relation_name, panels=None, label='', help_text=''): FieldPanel('seo_title'), FieldPanel('show_in_menus'), FieldPanel('search_description'), + FieldPanel('go_live_at'), + FieldPanel('expire_at'), ], ugettext_lazy('Common page configuration')), ] From 97ab613f88ab742c57400f0985d73b62be341635 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 10:28:00 +0100 Subject: [PATCH 039/293] Moved tests for publish pages command into wagtailcore --- wagtail/wagtailadmin/tests.py | 107 +-------------------------------- wagtail/wagtailcore/tests.py | 109 +++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 108 deletions(-) diff --git a/wagtail/wagtailadmin/tests.py b/wagtail/wagtailadmin/tests.py index 4d6016609f4..c657c1efbc7 100644 --- a/wagtail/wagtailadmin/tests.py +++ b/wagtail/wagtailadmin/tests.py @@ -1,12 +1,10 @@ -from datetime import datetime, timedelta -from django.core import management +from datetime import timedelta from django.core.urlresolvers import reverse from django.utils import timezone from django.test import TestCase from wagtail.tests.models import SimplePage, EventPage from wagtail.tests.utils import login, unittest from wagtail.wagtailcore.models import Page, PageRevision -from django.core.urlresolvers import reverse class TestHome(TestCase): @@ -472,106 +470,3 @@ def test_editor_css_and_js_hooks_on_edit(self): self.assertEqual(response.status_code, 200) self.assertContains(response, '') self.assertContains(response, '') - -class TestPublishScheduledPages(TestCase): - def setUp(self): - # Find root page - self.root_page = Page.objects.get(id=2) - - def test_go_live_page_will_be_published(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = False - page.go_live_at = timezone.now() - timedelta(days=1) - self.root_page.add_child(instance=page) - - page.save_revision( - approved_go_live_at = timezone.now() - timedelta(days=1) - ) - p = Page.objects.get(slug='hello-world') - self.assertFalse(p.live) - self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) - management.call_command('publish_scheduled_pages', verbosity=3, interactive=False) - #management.call_command('publish_scheduled_pages', dryrun=True, verbosity=3, interactive=False) - p = Page.objects.get(slug='hello-world') - self.assertTrue(p.live) - self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) - - def test_go_live_page_will_be_published(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = False - page.go_live_at = timezone.now() - timedelta(days=1) - self.root_page.add_child(instance=page) - - page.save_revision(approved_go_live_at = timezone.now() - timedelta(days=1)) - p = Page.objects.get(slug='hello-world') - self.assertFalse(p.live) - self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) - management.call_command('publish_scheduled_pages', ) - p = Page.objects.get(slug='hello-world') - self.assertTrue(p.live) - self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) - - def test_future_go_live_page_will_not_be_published(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = False - page.go_live_at = timezone.now() + timedelta(days=1) - self.root_page.add_child(instance=page) - page.save_revision(approved_go_live_at = timezone.now() - timedelta(days=1)) - p = Page.objects.get(slug='hello-world') - self.assertFalse(p.live) - self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) - management.call_command('publish_scheduled_pages', ) - p = Page.objects.get(slug='hello-world') - self.assertFalse(p.live) - self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) - - def test_expired_page_will_be_unpublished(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = True - page.expire_at = timezone.now() - timedelta(days=1) - self.root_page.add_child(instance=page) - p = Page.objects.get(slug='hello-world') - self.assertTrue(p.live) - management.call_command('publish_scheduled_pages', ) - p = Page.objects.get(slug='hello-world') - self.assertFalse(p.live) - self.assertTrue(p.expired) - - def test_future_expired_page_will_not_be_unpublished(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = True - page.expire_at = timezone.now() + timedelta(days=1) - self.root_page.add_child(instance=page) - p = Page.objects.get(slug='hello-world') - self.assertTrue(p.live) - management.call_command('publish_scheduled_pages', ) - p = Page.objects.get(slug='hello-world') - self.assertTrue(p.live) - self.assertFalse(p.expired) - - def test_expired_pages_are_dropped_from_mod_queue(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = False - page.expire_at = timezone.now() - timedelta(days=1) - self.root_page.add_child(instance=page) - page.save_revision(submitted_for_moderation = True) - p = Page.objects.get(slug='hello-world') - self.assertFalse(p.live) - self.assertTrue(PageRevision.objects.filter(page=p, submitted_for_moderation=True).exists()) - management.call_command('publish_scheduled_pages', ) - p = Page.objects.get(slug='hello-world') - self.assertFalse(PageRevision.objects.filter(page=p, submitted_for_moderation=True).exists()) - - diff --git a/wagtail/wagtailcore/tests.py b/wagtail/wagtailcore/tests.py index 1b12c10251c..3eede0e4a1b 100644 --- a/wagtail/wagtailcore/tests.py +++ b/wagtail/wagtailcore/tests.py @@ -1,9 +1,12 @@ +from datetime import timedelta + from django.test import TestCase, Client from django.http import HttpRequest, Http404 - +from django.utils import timezone from django.contrib.auth.models import User +from django.core import management -from wagtail.wagtailcore.models import Page, Site, UserPagePermissionsProxy +from wagtail.wagtailcore.models import Page, Site, UserPagePermissionsProxy, PageRevision from wagtail.tests.models import EventPage, EventIndex, SimplePage @@ -776,3 +779,105 @@ def test_issue157(self): # Check url self.assertEqual(homepage.url, '/') + + +class TestPublishScheduledPagesCommand(TestCase): + def setUp(self): + # Find root page + self.root_page = Page.objects.get(id=2) + + def test_go_live_page_will_be_published(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = False + page.go_live_at = timezone.now() - timedelta(days=1) + self.root_page.add_child(instance=page) + + page.save_revision( + approved_go_live_at = timezone.now() - timedelta(days=1) + ) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) + management.call_command('publish_scheduled_pages', verbosity=3, interactive=False) + #management.call_command('publish_scheduled_pages', dryrun=True, verbosity=3, interactive=False) + p = Page.objects.get(slug='hello-world') + self.assertTrue(p.live) + self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) + + def test_go_live_page_will_be_published(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = False + page.go_live_at = timezone.now() - timedelta(days=1) + self.root_page.add_child(instance=page) + + page.save_revision(approved_go_live_at = timezone.now() - timedelta(days=1)) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) + management.call_command('publish_scheduled_pages', ) + p = Page.objects.get(slug='hello-world') + self.assertTrue(p.live) + self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) + + def test_future_go_live_page_will_not_be_published(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = False + page.go_live_at = timezone.now() + timedelta(days=1) + self.root_page.add_child(instance=page) + page.save_revision(approved_go_live_at = timezone.now() - timedelta(days=1)) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) + management.call_command('publish_scheduled_pages', ) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) + + def test_expired_page_will_be_unpublished(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = True + page.expire_at = timezone.now() - timedelta(days=1) + self.root_page.add_child(instance=page) + p = Page.objects.get(slug='hello-world') + self.assertTrue(p.live) + management.call_command('publish_scheduled_pages', ) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(p.expired) + + def test_future_expired_page_will_not_be_unpublished(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = True + page.expire_at = timezone.now() + timedelta(days=1) + self.root_page.add_child(instance=page) + p = Page.objects.get(slug='hello-world') + self.assertTrue(p.live) + management.call_command('publish_scheduled_pages', ) + p = Page.objects.get(slug='hello-world') + self.assertTrue(p.live) + self.assertFalse(p.expired) + + def test_expired_pages_are_dropped_from_mod_queue(self): + page = SimplePage() + page.title = "Hello world!" + page.slug = "hello-world" + page.live = False + page.expire_at = timezone.now() - timedelta(days=1) + self.root_page.add_child(instance=page) + page.save_revision(submitted_for_moderation = True) + p = Page.objects.get(slug='hello-world') + self.assertFalse(p.live) + self.assertTrue(PageRevision.objects.filter(page=p, submitted_for_moderation=True).exists()) + management.call_command('publish_scheduled_pages', ) + p = Page.objects.get(slug='hello-world') + self.assertFalse(PageRevision.objects.filter(page=p, submitted_for_moderation=True).exists()) From e530531cb9be2c2b398ce374b73294eca27d1eeb Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 10:37:39 +0100 Subject: [PATCH 040/293] Cleanup of scheduled publishing tests --- wagtail/wagtailadmin/tests.py | 11 ++++ wagtail/wagtailcore/tests.py | 109 ++++++++++++++++++++-------------- 2 files changed, 77 insertions(+), 43 deletions(-) diff --git a/wagtail/wagtailadmin/tests.py b/wagtail/wagtailadmin/tests.py index c657c1efbc7..3e4103137d9 100644 --- a/wagtail/wagtailadmin/tests.py +++ b/wagtail/wagtailadmin/tests.py @@ -1,7 +1,9 @@ from datetime import timedelta + from django.core.urlresolvers import reverse from django.utils import timezone from django.test import TestCase + from wagtail.tests.models import SimplePage, EventPage from wagtail.tests.utils import login, unittest from wagtail.wagtailcore.models import Page, PageRevision @@ -266,8 +268,10 @@ def test_edit_post_scheduled(self): # The page will still be live self.assertTrue(child_page_new.live) + # A revision with approved_go_live_at should not exist self.assertFalse(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_at__isnull=True).exists()) + # But a revision with go_live_at and expire_at in their content json *should* exist self.assertTrue(PageRevision.objects.filter(page=child_page_new, content_json__contains=str(go_live_at.date())).exists()) self.assertTrue(PageRevision.objects.filter(page=child_page_new, content_json__contains=str(expire_at.date())).exists()) @@ -309,8 +313,10 @@ def test_edit_post_publish_scheduled(self): self.assertEqual(response.status_code, 302) child_page_new = SimplePage.objects.get(id=self.child_page.id) + # The page should not be live anymore self.assertFalse(child_page_new.live) + # Instead a revision with approved_go_live_at should now exist self.assertTrue(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_at__isnull=True).exists()) @@ -332,8 +338,10 @@ def test_edit_post_publish_now_an_already_scheduled(self): self.assertEqual(response.status_code, 302) child_page_new = SimplePage.objects.get(id=self.child_page.id) + # The page should not be live anymore self.assertFalse(child_page_new.live) + # Instead a revision with approved_go_live_at should now exist self.assertTrue(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_at__isnull=True).exists()) @@ -352,11 +360,14 @@ def test_edit_post_publish_now_an_already_scheduled(self): self.assertEqual(response.status_code, 302) child_page_new = SimplePage.objects.get(id=self.child_page.id) + # The page should be live now self.assertTrue(child_page_new.live) + # And a revision with approved_go_live_at should not exist self.assertFalse(PageRevision.objects.filter(page=child_page_new).exclude(approved_go_live_at__isnull=True).exists()) + class TestPageDelete(TestCase): def setUp(self): # Find root page diff --git a/wagtail/wagtailcore/tests.py b/wagtail/wagtailcore/tests.py index 3eede0e4a1b..32ec3a826ec 100644 --- a/wagtail/wagtailcore/tests.py +++ b/wagtail/wagtailcore/tests.py @@ -787,97 +787,120 @@ def setUp(self): self.root_page = Page.objects.get(id=2) def test_go_live_page_will_be_published(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = False - page.go_live_at = timezone.now() - timedelta(days=1) + page = SimplePage( + title="Hello world!", + slug="hello-world", + live=False, + go_live_at=timezone.now() - timedelta(days=1), + ) self.root_page.add_child(instance=page) - page.save_revision( - approved_go_live_at = timezone.now() - timedelta(days=1) - ) + page.save_revision(approved_go_live_at=timezone.now() - timedelta(days=1)) + p = Page.objects.get(slug='hello-world') self.assertFalse(p.live) self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) - management.call_command('publish_scheduled_pages', verbosity=3, interactive=False) - #management.call_command('publish_scheduled_pages', dryrun=True, verbosity=3, interactive=False) + + management.call_command('publish_scheduled_pages') + p = Page.objects.get(slug='hello-world') self.assertTrue(p.live) self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) def test_go_live_page_will_be_published(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = False - page.go_live_at = timezone.now() - timedelta(days=1) + page = SimplePage( + title="Hello world!", + slug="hello-world", + live=False, + go_live_at=timezone.now() - timedelta(days=1), + ) self.root_page.add_child(instance=page) - page.save_revision(approved_go_live_at = timezone.now() - timedelta(days=1)) + page.save_revision(approved_go_live_at=timezone.now() - timedelta(days=1)) + p = Page.objects.get(slug='hello-world') self.assertFalse(p.live) self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) - management.call_command('publish_scheduled_pages', ) + + management.call_command('publish_scheduled_pages') + p = Page.objects.get(slug='hello-world') self.assertTrue(p.live) self.assertFalse(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) def test_future_go_live_page_will_not_be_published(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = False - page.go_live_at = timezone.now() + timedelta(days=1) + page = SimplePage( + title="Hello world!", + slug="hello-world", + live=False, + go_live_at=timezone.now() + timedelta(days=1), + ) self.root_page.add_child(instance=page) - page.save_revision(approved_go_live_at = timezone.now() - timedelta(days=1)) + + page.save_revision(approved_go_live_at=timezone.now() - timedelta(days=1)) + p = Page.objects.get(slug='hello-world') self.assertFalse(p.live) self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) - management.call_command('publish_scheduled_pages', ) + + management.call_command('publish_scheduled_pages') + p = Page.objects.get(slug='hello-world') self.assertFalse(p.live) self.assertTrue(PageRevision.objects.filter(page=p).exclude(approved_go_live_at__isnull=True).exists()) def test_expired_page_will_be_unpublished(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = True - page.expire_at = timezone.now() - timedelta(days=1) + page = SimplePage( + title="Hello world!", + slug="hello-world", + live=True, + expire_at=timezone.now() - timedelta(days=1), + ) self.root_page.add_child(instance=page) + p = Page.objects.get(slug='hello-world') self.assertTrue(p.live) - management.call_command('publish_scheduled_pages', ) + + management.call_command('publish_scheduled_pages') + p = Page.objects.get(slug='hello-world') self.assertFalse(p.live) self.assertTrue(p.expired) def test_future_expired_page_will_not_be_unpublished(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = True - page.expire_at = timezone.now() + timedelta(days=1) + page = SimplePage( + title="Hello world!", + slug="hello-world", + live=True, + expire_at=timezone.now() + timedelta(days=1), + ) self.root_page.add_child(instance=page) + p = Page.objects.get(slug='hello-world') self.assertTrue(p.live) - management.call_command('publish_scheduled_pages', ) + + management.call_command('publish_scheduled_pages') + p = Page.objects.get(slug='hello-world') self.assertTrue(p.live) self.assertFalse(p.expired) def test_expired_pages_are_dropped_from_mod_queue(self): - page = SimplePage() - page.title = "Hello world!" - page.slug = "hello-world" - page.live = False - page.expire_at = timezone.now() - timedelta(days=1) + page = SimplePage( + title="Hello world!", + slug="hello-world", + live=False, + expire_at=timezone.now() - timedelta(days=1), + ) self.root_page.add_child(instance=page) - page.save_revision(submitted_for_moderation = True) + + page.save_revision(submitted_for_moderation=True) + p = Page.objects.get(slug='hello-world') self.assertFalse(p.live) self.assertTrue(PageRevision.objects.filter(page=p, submitted_for_moderation=True).exists()) - management.call_command('publish_scheduled_pages', ) + + management.call_command('publish_scheduled_pages') + p = Page.objects.get(slug='hello-world') self.assertFalse(PageRevision.objects.filter(page=p, submitted_for_moderation=True).exists()) From c7e6c429543c883bec025cf41f0f477a0ce5a67e Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 12:56:15 +0100 Subject: [PATCH 041/293] A couple of minor coding style fixes --- wagtail/wagtailadmin/views/pages.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index f4ea960ffc8..55040366c20 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -157,7 +157,7 @@ def clean_slug(slug): page.save_revision( user=request.user, submitted_for_moderation=is_submitting, - approved_go_live_at = approved_go_live_at + approved_go_live_at=approved_go_live_at ) if is_publishing: @@ -255,7 +255,7 @@ def clean_slug(slug): page.save_revision( user=request.user, submitted_for_moderation=is_submitting, - approved_go_live_at = approved_go_live_at + approved_go_live_at=approved_go_live_at ) if is_publishing: From 0d7471b94f9f92454aa0c093892b0cd2ccdf1219 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 14:58:49 +0100 Subject: [PATCH 042/293] Installed jQuery.datetimepicker https://github.com/xdan/datetimepicker/commit/3e320c9046f9c735bbff1c9e39056f --- .../js/vendor/jquery.datetimepicker.js | 1363 +++++++++++++++++ .../scss/vendor/jquery.datetimepicker.css | 304 ++++ .../templates/wagtailadmin/admin_base.html | 2 + 3 files changed, 1669 insertions(+) create mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/jquery.datetimepicker.js create mode 100644 wagtail/wagtailadmin/static/wagtailadmin/scss/vendor/jquery.datetimepicker.css diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/jquery.datetimepicker.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/jquery.datetimepicker.js new file mode 100644 index 00000000000..cf7b9249597 --- /dev/null +++ b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/jquery.datetimepicker.js @@ -0,0 +1,1363 @@ +/** + * @preserve jQuery DateTimePicker plugin v2.2.8 + * @homepage http://xdsoft.net/jqplugins/datetimepicker/ + * (c) 2014, Chupurnov Valeriy. + */ +(function( $ ) { + 'use strict'; + var default_options = { + i18n:{ + bg:{ // Bulgarian + months:[ + "Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември" + ], + dayOfWeek:[ + "Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб" + ] + }, + fa:{ // Persian/Farsi + months:[ + 'فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند' + ], + dayOfWeek:[ + 'یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه' + ] + }, + ru:{ // Russian + months:[ + 'Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь' + ], + dayOfWeek:[ + "Вск", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб" + ] + }, + en:{ // English + months: [ + "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" + ], + dayOfWeek: [ + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + ] + }, + el:{ // Ελληνικά + months: [ + "Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος" + ], + dayOfWeek: [ + "Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ" + ] + }, + de:{ // German + months:[ + 'Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember' + ], + dayOfWeek:[ + "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa" + ] + }, + nl:{ // Dutch + months:[ + "januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december" + ], + dayOfWeek:[ + "zo", "ma", "di", "wo", "do", "vr", "za" + ] + }, + tr:{ // Turkish + months:[ + "Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık" + ], + dayOfWeek:[ + "Paz", "Pts", "Sal", "Çar", "Per", "Cum", "Cts" + ] + }, + fr:{ //French + months:[ + "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" + ], + dayOfWeek:[ + "Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam" + ] + }, + es:{ // Spanish + months: [ + "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre" + ], + dayOfWeek: [ + "Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb" + ] + }, + th:{ // Thai + months:[ + 'มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน','กรกฎาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม' + ], + dayOfWeek:[ + 'อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.' + ] + }, + pl:{ // Polish + months: [ + "styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec", "lipiec", "sierpień", "wrzesień", "październik", "listopad", "grudzień" + ], + dayOfWeek: [ + "nd", "pn", "wt", "śr", "cz", "pt", "sb" + ] + }, + pt:{ // Portuguese + months: [ + "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro" + ], + dayOfWeek: [ + "Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab" + ] + }, + ch:{ // Simplified Chinese + months: [ + "一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月" + ], + dayOfWeek: [ + "日", "一","二","三","四","五","六" + ] + }, + se:{ // Swedish + months: [ + "Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September","Oktober", "November", "December" + ], + dayOfWeek: [ + "Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör" + ] + }, + kr:{ // Korean + months: [ + "1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월" + ], + dayOfWeek: [ + "일", "월", "화", "수", "목", "금", "토" + ] + }, + it:{ // Italian + months: [ + "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre" + ], + dayOfWeek: [ + "Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab" + ] + }, + da:{ // Dansk + months: [ + "January", "Februar", "Marts", "April", "Maj", "Juni", "July", "August", "September", "Oktober", "November", "December" + ], + dayOfWeek: [ + "Søn", "Man", "Tir", "ons", "Tor", "Fre", "lør" + ] + }, + ja:{ // Japanese + months: [ + "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月" + ], + dayOfWeek: [ + "日", "月", "火", "水", "木", "金", "土" + ] + }, + vi:{ // Vietnamese + months: [ + "Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12" + ], + dayOfWeek: [ + "CN", "T2", "T3", "T4", "T5", "T6", "T7" + ] + }, + sl:{ // Slovenščina + months: [ + "Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December" + ], + dayOfWeek: [ + "Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob" + ] + } + }, + value:'', + lang:'en', + + format: 'Y/m/d H:i', + formatTime: 'H:i', + formatDate: 'Y/m/d', + + startDate: false, // new Date(), '1986/12/08', '-1970/01/05','-1970/01/05', + + step:60, + monthChangeSpinner:true, + closeOnDateSelect:false, + closeOnWithoutClick:true, + + timepicker:true, + datepicker:true, + + minDate:false, + maxDate:false, + minTime:false, + maxTime:false, + + allowTimes:[], + opened:false, + initTime:true, + inline:false, + + onSelectDate:function() {}, + onSelectTime:function() {}, + onChangeMonth:function() {}, + onChangeDateTime:function() {}, + onShow:function() {}, + onClose:function() {}, + onGenerate:function() {}, + + withoutCopyright:true, + + inverseButton:false, + hours12:false, + next: 'xdsoft_next', + prev : 'xdsoft_prev', + dayOfWeekStart:0, + + timeHeightInTimePicker:25, + timepickerScrollbar:true, + + todayButton:true, // 2.1.0 + defaultSelect:true, // 2.1.0 + + scrollMonth:true, + scrollTime:true, + scrollInput:true, + + lazyInit:false, + + mask:false, + validateOnBlur:true, + allowBlank:true, + + yearStart:1950, + yearEnd:2050, + + style:'', + id:'', + + fixed: false, + + roundTime:'round', // ceil, floor + className:'', + + weekends : [], + yearOffset:0 + }; + + // fix for ie8 + if ( !Array.prototype.indexOf ) { + Array.prototype.indexOf = function(obj, start) { + for (var i = (start || 0), j = this.length; i < j; i++) { + if (this[i] === obj) { return i; } + } + return -1; + } + }; + + Date.prototype.countDaysInMonth = function(){ + return new Date(this.getFullYear(), this.getMonth()+1, 0).getDate(); + }; + + $.fn.xdsoftScroller = function( _percent ) { + return this.each(function() { + var timeboxparent = $(this); + if( !$(this).hasClass('xdsoft_scroller_box') ) { + var pointerEventToXY = function( e ) { + var out = {x:0, y:0}; + if( e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel' ) { + var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0]; + out.x = touch.pageX; + out.y = touch.pageY; + }else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover'|| e.type=='mouseout' || e.type=='mouseenter' || e.type=='mouseleave') { + out.x = e.pageX; + out.y = e.pageY; + } + return out; + }, + move = 0, + timebox = timeboxparent.children().eq(0), + parentHeight = timeboxparent[0].clientHeight, + height = timebox[0].offsetHeight, + scrollbar = $('
      '), + scroller = $('
      '), + maximumOffset = 100, + start = false; + + scrollbar.append(scroller); + + timeboxparent.addClass('xdsoft_scroller_box').append(scrollbar); + scroller.on('mousedown.xdsoft_scroller',function ( event ) { + if( !parentHeight ) + timeboxparent.trigger('resize_scroll.xdsoft_scroller',[_percent]); + var pageY = event.pageY, + top = parseInt(scroller.css('margin-top')), + h1 = scrollbar[0].offsetHeight; + $(document.body).addClass('xdsoft_noselect'); + $([document.body,window]).on('mouseup.xdsoft_scroller',function arguments_callee() { + $([document.body,window]).off('mouseup.xdsoft_scroller',arguments_callee) + .off('mousemove.xdsoft_scroller',move) + .removeClass('xdsoft_noselect'); + }); + $(document.body).on('mousemove.xdsoft_scroller',move = function(event) { + var offset = event.pageY-pageY+top; + if( offset<0 ) + offset = 0; + if( offset+scroller[0].offsetHeight>h1 ) + offset = h1-scroller[0].offsetHeight; + timeboxparent.trigger('scroll_element.xdsoft_scroller',[maximumOffset?offset/maximumOffset:0]); + }); + }); + + timeboxparent + .on('scroll_element.xdsoft_scroller',function( event,percent ) { + if( !parentHeight ) + timeboxparent.trigger('resize_scroll.xdsoft_scroller',[percent,true]); + percent = percent>1?1:(percent<0||isNaN(percent))?0:percent; + scroller.css('margin-top',maximumOffset*percent); + timebox.css('marginTop',-parseInt((height-parentHeight)*percent)) + }) + .on('resize_scroll.xdsoft_scroller',function( event,_percent,noTriggerScroll ) { + parentHeight = timeboxparent[0].clientHeight; + height = timebox[0].offsetHeight; + var percent = parentHeight/height, + sh = percent*scrollbar[0].offsetHeight; + if( percent>1 ) + scroller.hide(); + else{ + scroller.show(); + scroller.css('height',parseInt(sh>10?sh:10)); + maximumOffset = scrollbar[0].offsetHeight-scroller[0].offsetHeight; + if( noTriggerScroll!==true ) + timeboxparent.trigger('scroll_element.xdsoft_scroller',[_percent?_percent:Math.abs(parseInt(timebox.css('marginTop')))/(height-parentHeight)]); + } + }); + timeboxparent.mousewheel&&timeboxparent.mousewheel(function(event, delta, deltaX, deltaY) { + var top = Math.abs(parseInt(timebox.css('marginTop'))); + timeboxparent.trigger('scroll_element.xdsoft_scroller',[(top-delta*20)/(height-parentHeight)]); + event.stopPropagation(); + return false; + }); + timeboxparent.on('touchstart',function( event ) { + start = pointerEventToXY(event); + }); + timeboxparent.on('touchmove',function( event ) { + if( start ) { + var coord = pointerEventToXY(event), top = Math.abs(parseInt(timebox.css('marginTop'))); + timeboxparent.trigger('scroll_element.xdsoft_scroller',[(top-(coord.y-start.y))/(height-parentHeight)]); + event.stopPropagation(); + event.preventDefault(); + }; + }); + timeboxparent.on('touchend touchcancel',function( event ) { + start = false; + }); + } + timeboxparent.trigger('resize_scroll.xdsoft_scroller',[_percent]); + }); + }; + $.fn.datetimepicker = function( opt ) { + var KEY0 = 48, + KEY9 = 57, + _KEY0 = 96, + _KEY9 = 105, + CTRLKEY = 17, + DEL = 46, + ENTER = 13, + ESC = 27, + BACKSPACE = 8, + ARROWLEFT = 37, + ARROWUP = 38, + ARROWRIGHT = 39, + ARROWDOWN = 40, + TAB = 9, + F5 = 116, + AKEY = 65, + CKEY = 67, + VKEY = 86, + ZKEY = 90, + YKEY = 89, + ctrlDown = false, + options = ($.isPlainObject(opt)||!opt)?$.extend(true,{},default_options,opt):$.extend({},default_options), + + lazyInitTimer = 0, + + lazyInit = function( input ){ + input + .on('open.xdsoft focusin.xdsoft mousedown.xdsoft',function initOnActionCallback(event) { + if( input.is(':disabled')||input.is(':hidden')||!input.is(':visible')||input.data( 'xdsoft_datetimepicker') ) + return; + + clearTimeout(lazyInitTimer); + + lazyInitTimer = setTimeout(function() { + + if( !input.data( 'xdsoft_datetimepicker') ) + createDateTimePicker(input); + + input + .off('open.xdsoft focusin.xdsoft mousedown.xdsoft',initOnActionCallback) + .trigger('open.xdsoft'); + },100); + + }); + }, + + createDateTimePicker = function( input ) { + + var datetimepicker = $('
      '), + xdsoft_copyright = $(''), + datepicker = $('
      '), + mounth_picker = $('
      '), + calendar = $('
      '), + timepicker = $('
      '), + timeboxparent = timepicker.find('.xdsoft_time_box').eq(0), + timebox = $('
      '), + scrollbar = $('
      '), + scroller = $('
      '), + monthselect =$('
      '), + yearselect =$('
      '); + + //constructor lego + mounth_picker + .find('.xdsoft_month span') + .after(monthselect); + mounth_picker + .find('.xdsoft_year span') + .after(yearselect); + + mounth_picker + .find('.xdsoft_month,.xdsoft_year') + .on('mousedown.xdsoft',function(event) { + mounth_picker + .find('.xdsoft_select') + .hide(); + + var select = $(this).find('.xdsoft_select').eq(0), + val = 0, + top = 0; + + if( _xdsoft_datetime.currentTime ) + val = _xdsoft_datetime.currentTime[$(this).hasClass('xdsoft_month')?'getMonth':'getFullYear'](); + + select.show(); + + for(var items = select.find('div.xdsoft_option'),i = 0;i6 ) + options.dayOfWeekStart = 0; + else + options.dayOfWeekStart = parseInt(options.dayOfWeekStart); + + if( !options.timepickerScrollbar ) + scrollbar.hide(); + + if( options.minDate && /^-(.*)$/.test(options.minDate) ){ + options.minDate = _xdsoft_datetime.strToDateTime(options.minDate).dateFormat( options.formatDate ); + } + + if( options.maxDate && /^\+(.*)$/.test(options.maxDate) ) { + options.maxDate = _xdsoft_datetime.strToDateTime(options.maxDate).dateFormat( options.formatDate ); + } + + mounth_picker + .find('.xdsoft_today_button') + .css('visibility',!options.todayButton?'hidden':'visible'); + + if( options.mask ) { + var e, + getCaretPos = function ( input ) { + try{ + if ( document.selection && document.selection.createRange ) { + var range = document.selection.createRange(); + return range.getBookmark().charCodeAt(2) - 2; + }else + if ( input.setSelectionRange ) + return input.selectionStart; + }catch(e) { + return 0; + } + }, + setCaretPos = function ( node,pos ) { + var node = (typeof node == "string" || node instanceof String) ? document.getElementById(node) : node; + if(!node) { + return false; + }else if(node.createTextRange) { + var textRange = node.createTextRange(); + textRange.collapse(true); + textRange.moveEnd(pos); + textRange.moveStart(pos); + textRange.select(); + return true; + }else if(node.setSelectionRange) { + node.setSelectionRange(pos,pos); + return true; + } + return false; + }, + isValidValue = function ( mask,value ) { + var reg = mask + .replace(/([\[\]\/\{\}\(\)\-\.\+]{1})/g,'\\$1') + .replace(/_/g,'{digit+}') + .replace(/([0-9]{1})/g,'{digit$1}') + .replace(/\{digit([0-9]{1})\}/g,'[0-$1_]{1}') + .replace(/\{digit[\+]\}/g,'[0-9_]{1}'); + return RegExp(reg).test(value); + }; + input.off('keydown.xdsoft'); + switch(true) { + case ( options.mask===true ): + + options.mask = options.format + .replace(/Y/g,'9999') + .replace(/F/g,'9999') + .replace(/m/g,'19') + .replace(/d/g,'39') + .replace(/H/g,'29') + .replace(/i/g,'59') + .replace(/s/g,'59'); + + case ( $.type(options.mask) == 'string' ): + + if( !isValidValue( options.mask,input.val() ) ) + input.val(options.mask.replace(/[0-9]/g,'_')); + + input.on('keydown.xdsoft',function( event ) { + var val = this.value, + key = event.which; + + switch(true) { + case (( key>=KEY0&&key<=KEY9 )||( key>=_KEY0&&key<=_KEY9 ))||(key==BACKSPACE||key==DEL): + var pos = getCaretPos(this), + digit = ( key!=BACKSPACE&&key!=DEL )?String.fromCharCode((_KEY0 <= key && key <= _KEY9)? key-KEY0 : key):'_'; + + if( (key==BACKSPACE||key==DEL)&&pos ) { + pos--; + digit='_'; + } + + while( /[^0-9_]/.test(options.mask.substr(pos,1))&&pos0 ) + pos+=( key==BACKSPACE||key==DEL )?-1:1; + + val = val.substr(0,pos)+digit+val.substr(pos+1); + if( $.trim(val)=='' ){ + val = options.mask.replace(/[0-9]/g,'_'); + }else{ + if( pos==options.mask.length ) + break; + } + + pos+=(key==BACKSPACE||key==DEL)?0:1; + while( /[^0-9_]/.test(options.mask.substr(pos,1))&&pos0 ) + pos+=(key==BACKSPACE||key==DEL)?-1:1; + + if( isValidValue( options.mask,val ) ) { + this.value = val; + setCaretPos(this,pos); + }else if( $.trim(val)=='' ) + this.value = options.mask.replace(/[0-9]/g,'_'); + else{ + input.trigger('error_input.xdsoft'); + } + break; + case ( !!~([AKEY,CKEY,VKEY,ZKEY,YKEY].indexOf(key))&&ctrlDown ): + case !!~([ESC,ARROWUP,ARROWDOWN,ARROWLEFT,ARROWRIGHT,F5,CTRLKEY,TAB,ENTER].indexOf(key)): + return true; + } + event.preventDefault(); + return false; + }); + break; + } + } + if( options.validateOnBlur ) { + input + .off('blur.xdsoft') + .on('blur.xdsoft', function() { + if( options.allowBlank && !$.trim($(this).val()).length ) { + $(this).val(null); + datetimepicker.data('xdsoft_datetime').empty(); + }else if( !Date.parseDate( $(this).val(), options.format ) ) { + $(this).val((_xdsoft_datetime.now()).dateFormat( options.format )); + datetimepicker.data('xdsoft_datetime').setCurrentTime($(this).val()); + } + else{ + datetimepicker.data('xdsoft_datetime').setCurrentTime($(this).val()); + } + datetimepicker.trigger('changedatetime.xdsoft'); + }); + } + options.dayOfWeekStartPrev = (options.dayOfWeekStart==0)?6:options.dayOfWeekStart-1; + + datetimepicker + .trigger('xchange.xdsoft') + .trigger('afterOpen.xdsoft') + }; + + datetimepicker + .data('options',options) + .on('mousedown.xdsoft',function( event ) { + event.stopPropagation(); + event.preventDefault(); + yearselect.hide(); + monthselect.hide(); + return false; + }); + + var scroll_element = timepicker.find('.xdsoft_time_box'); + scroll_element.append(timebox); + scroll_element.xdsoftScroller(); + + datetimepicker.on('afterOpen.xdsoft',function() { + scroll_element.xdsoftScroller(); + }); + + datetimepicker + .append(datepicker) + .append(timepicker); + + if( options.withoutCopyright!==true ) + datetimepicker + .append(xdsoft_copyright); + + datepicker + .append(mounth_picker) + .append(calendar); + + $('body').append(datetimepicker); + + var _xdsoft_datetime = new function() { + var _this = this; + _this.now = function() { + var d = new Date(); + if( options.yearOffset ) + d.setFullYear(d.getFullYear()+options.yearOffset); + return d; + }; + + _this.currentTime = this.now(); + _this.isValidDate = function (d) { + if ( Object.prototype.toString.call(d) !== "[object Date]" ) + return false; + return !isNaN(d.getTime()); + }; + + _this.setCurrentTime = function( dTime) { + _this.currentTime = (typeof dTime == 'string')? _this.strToDateTime(dTime) : _this.isValidDate(dTime) ? dTime: _this.now(); + datetimepicker.trigger('xchange.xdsoft'); + }; + + _this.empty = function() { + _this.currentTime = null; + }; + + _this.getCurrentTime = function( dTime) { + return _this.currentTime; + }; + + _this.nextMonth = function() { + var month = _this.currentTime.getMonth()+1; + if( month==12 ) { + _this.currentTime.setFullYear(_this.currentTime.getFullYear()+1); + month = 0; + } + _this.currentTime.setDate( + Math.min( + Date.daysInMonth[month], + _this.currentTime.getDate() + ) + ); + _this.currentTime.setMonth(month); + options.onChangeMonth&&options.onChangeMonth.call&&options.onChangeMonth.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input')); + datetimepicker.trigger('xchange.xdsoft'); + return month; + }; + + _this.prevMonth = function() { + var month = _this.currentTime.getMonth()-1; + if( month==-1 ) { + _this.currentTime.setFullYear(_this.currentTime.getFullYear()-1); + month = 11; + } + _this.currentTime.setDate( + Math.min( + Date.daysInMonth[month], + _this.currentTime.getDate() + ) + ); + _this.currentTime.setMonth(month); + options.onChangeMonth&&options.onChangeMonth.call&&options.onChangeMonth.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input')); + datetimepicker.trigger('xchange.xdsoft'); + return month; + }; + + _this.strToDateTime = function( sDateTime ) { + var tmpDate = [],timeOffset,currentTime; + + if( ( tmpDate = /^(\+|\-)(.*)$/.exec(sDateTime) ) && ( tmpDate[2]=Date.parseDate(tmpDate[2], options.formatDate) ) ) { + timeOffset = tmpDate[2].getTime()-(tmpDate[2].getTimezoneOffset())*60000; + currentTime = new Date((_xdsoft_datetime.now()).getTime()+parseInt(tmpDate[1]+'1')*timeOffset); + }else + currentTime = sDateTime?Date.parseDate(sDateTime, options.format):_this.now(); + + if( !_this.isValidDate(currentTime) ) + currentTime = _this.now(); + + return currentTime; + }; + + _this.strtodate = function( sDate ) { + var currentTime = sDate?Date.parseDate(sDate, options.formatDate):_this.now(); + if( !_this.isValidDate(currentTime) ) + currentTime = _this.now(); + return currentTime; + }; + + _this.strtotime = function( sTime ) { + var currentTime = sTime?Date.parseDate(sTime, options.formatTime):_this.now(); + if( !_this.isValidDate(currentTime) ) + currentTime = _this.now(); + return currentTime; + }; + + _this.str = function() { + return _this.currentTime.dateFormat(options.format); + }; + }; + mounth_picker + .find('.xdsoft_today_button') + .on('mousedown.xdsoft',function() { + datetimepicker.data('changed',true); + _xdsoft_datetime.setCurrentTime(0); + datetimepicker.trigger('afterOpen.xdsoft'); + }).on('dblclick.xdsoft',function(){ + input.val( _xdsoft_datetime.str() ); + datetimepicker.trigger('close.xdsoft'); + }); + mounth_picker + .find('.xdsoft_prev,.xdsoft_next') + .on('mousedown.xdsoft',function() { + var $this = $(this), + timer = 0, + stop = false; + + (function arguments_callee1(v) { + var month = _xdsoft_datetime.currentTime.getMonth(); + if( $this.hasClass( options.next ) ) { + _xdsoft_datetime.nextMonth(); + }else if( $this.hasClass( options.prev ) ) { + _xdsoft_datetime.prevMonth(); + } + if (options.monthChangeSpinner) { + !stop&&(timer = setTimeout(arguments_callee1,v?v:100)); + } + })(500); + + $([document.body,window]).on('mouseup.xdsoft',function arguments_callee2() { + clearTimeout(timer); + stop = true; + $([document.body,window]).off('mouseup.xdsoft',arguments_callee2); + }); + }); + + timepicker + .find('.xdsoft_prev,.xdsoft_next') + .on('mousedown.xdsoft',function() { + var $this = $(this), + timer = 0, + stop = false, + period = 110; + (function arguments_callee4(v) { + var pheight = timeboxparent[0].clientHeight, + height = timebox[0].offsetHeight, + top = Math.abs(parseInt(timebox.css('marginTop'))); + if( $this.hasClass(options.next) && (height-pheight)- options.timeHeightInTimePicker>=top ) { + timebox.css('marginTop','-'+(top+options.timeHeightInTimePicker)+'px') + }else if( $this.hasClass(options.prev) && top-options.timeHeightInTimePicker>=0 ) { + timebox.css('marginTop','-'+(top-options.timeHeightInTimePicker)+'px') + } + timeboxparent.trigger('scroll_element.xdsoft_scroller',[Math.abs(parseInt(timebox.css('marginTop'))/(height-pheight))]); + period= ( period>10 )?10:period-10; + !stop&&(timer = setTimeout(arguments_callee4,v?v:period)); + })(500); + $([document.body,window]).on('mouseup.xdsoft',function arguments_callee5() { + clearTimeout(timer); + stop = true; + $([document.body,window]) + .off('mouseup.xdsoft',arguments_callee5); + }); + }); + + var xchangeTimer = 0; + // base handler - generating a calendar and timepicker + datetimepicker + .on('xchange.xdsoft',function( event ) { + clearTimeout(xchangeTimer); + xchangeTimer = setTimeout(function(){ + var table = '', + start = new Date(_xdsoft_datetime.currentTime.getFullYear(),_xdsoft_datetime.currentTime.getMonth(),1, 12, 0, 0), + i = 0, + today = _xdsoft_datetime.now(); + + while( start.getDay()!=options.dayOfWeekStart ) + start.setDate(start.getDate()-1); + + //generate calendar + table+=''; + + // days + for(var j = 0; j<7; j++) { + table+=''; + } + + table+=''; + table+=''; + var maxDate = false, minDate = false; + + if( options.maxDate!==false ) { + maxDate = _xdsoft_datetime.strtodate(options.maxDate); + maxDate = new Date(maxDate.getFullYear(),maxDate.getMonth(),maxDate.getDate(),23,59,59,999); + } + + if( options.minDate!==false ) { + minDate = _xdsoft_datetime.strtodate(options.minDate); + minDate = new Date(minDate.getFullYear(),minDate.getMonth(),minDate.getDate()); + } + + var d,y,m,classes = []; + + while( i<_xdsoft_datetime.currentTime.countDaysInMonth()||start.getDay()!=options.dayOfWeekStart||_xdsoft_datetime.currentTime.getMonth()==start.getMonth() ) { + classes = []; + i++; + + d = start.getDate(); y = start.getFullYear(); m = start.getMonth(); + + classes.push('xdsoft_date'); + + if( ( maxDate!==false && start > maxDate )||( minDate!==false && start < minDate ) ){ + classes.push('xdsoft_disabled'); + } + + if( _xdsoft_datetime.currentTime.getMonth()!=m ){ + classes.push('xdsoft_other_month'); + } + + if( (options.defaultSelect||datetimepicker.data('changed')) && _xdsoft_datetime.currentTime.dateFormat( options.formatDate )==start.dateFormat( options.formatDate ) ) { + classes.push('xdsoft_current'); + } + + if( today.dateFormat( options.formatDate )==start.dateFormat( options.formatDate ) ) { + classes.push('xdsoft_today'); + } + + if( start.getDay()==0||start.getDay()==6||~options.weekends.indexOf(start.dateFormat( options.formatDate )) ) { + classes.push('xdsoft_weekend'); + } + + if(options.beforeShowDay && typeof options.beforeShowDay == 'function') + { + classes.push(options.beforeShowDay(start)) + } + + table+=''; + + if( start.getDay()==options.dayOfWeekStartPrev ) { + table+=''; + } + + start.setDate(d+1); + } + table+='
      '+options.i18n[options.lang].dayOfWeek[(j+options.dayOfWeekStart)>6?0:j+options.dayOfWeekStart]+'
      '+ + '
      '+d+'
      '+ + '
      '; + + calendar.html(table); + + mounth_picker.find('.xdsoft_label span').eq(0).text(options.i18n[options.lang].months[_xdsoft_datetime.currentTime.getMonth()]); + mounth_picker.find('.xdsoft_label span').eq(1).text(_xdsoft_datetime.currentTime.getFullYear()); + + // generate timebox + var time = '', + h = '', + m ='', + line_time = function line_time( h,m ) { + var now = _xdsoft_datetime.now(); + now.setHours(h); + h = parseInt(now.getHours()); + now.setMinutes(m); + m = parseInt(now.getMinutes()); + + classes = []; + if( (options.maxTime!==false&&_xdsoft_datetime.strtotime(options.maxTime).getTime()now.getTime())) + classes.push('xdsoft_disabled'); + if( (options.initTime||options.defaultSelect||datetimepicker.data('changed')) && parseInt(_xdsoft_datetime.currentTime.getHours())==parseInt(h)&&(options.step>59||Math[options.roundTime](_xdsoft_datetime.currentTime.getMinutes()/options.step)*options.step==parseInt(m))) { + if( options.defaultSelect||datetimepicker.data('changed')) { + classes.push('xdsoft_current'); + } else if( options.initTime ) { + classes.push('xdsoft_init_time'); + } + } + if( parseInt(today.getHours())==parseInt(h)&&parseInt(today.getMinutes())==parseInt(m)) + classes.push('xdsoft_today'); + time+= '
      '+now.dateFormat(options.formatTime)+'
      '; + }; + + if( !options.allowTimes || !$.isArray(options.allowTimes) || !options.allowTimes.length ) { + for( var i=0,j=0;i<(options.hours12?12:24);i++ ) { + for( j=0;j<60;j+=options.step ) { + h = (i<10?'0':'')+i; + m = (j<10?'0':'')+j; + line_time( h,m ); + } + } + }else{ + for( var i=0;i'+i+'
      '; + } + yearselect.children().eq(0) + .html(opt); + + for( i = 0,opt = '';i<= 11;i++ ) { + opt+='
      '+options.i18n[options.lang].months[i]+'
      '; + } + monthselect.children().eq(0).html(opt); + $(datetimepicker) + .trigger('generate.xdsoft'); + },10); + event.stopPropagation(); + }) + .on('afterOpen.xdsoft',function() { + if( options.timepicker ) { + var classType; + if( timebox.find('.xdsoft_current').length ) { + classType = '.xdsoft_current'; + } else if( timebox.find('.xdsoft_init_time').length ) { + classType = '.xdsoft_init_time'; + } + + if( classType ) { + var pheight = timeboxparent[0].clientHeight, + height = timebox[0].offsetHeight, + top = timebox.find(classType).index()*options.timeHeightInTimePicker+1; + if( (height-pheight)1||(options.closeOnDateSelect===true||( options.closeOnDateSelect===0&&!options.timepicker )))&&!options.inline ) { + datetimepicker.trigger('close.xdsoft'); + } + + if( options.onSelectDate && options.onSelectDate.call ) { + options.onSelectDate.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input')); + } + + datetimepicker.data('changed',true); + datetimepicker.trigger('xchange.xdsoft'); + datetimepicker.trigger('changedatetime.xdsoft'); + setTimeout(function(){ + timerclick = 0; + },200); + }); + + timebox + .on('click.xdsoft', 'div', function (xdevent) { + xdevent.stopPropagation(); // NAJ: Prevents closing of Pop-ups, Modals and Flyouts + var $this = $(this), + currentTime = _xdsoft_datetime.currentTime; + if( $this.hasClass('xdsoft_disabled') ) + return false; + currentTime.setHours($this.data('hour')); + currentTime.setMinutes($this.data('minute')); + datetimepicker.trigger('select.xdsoft',[currentTime]); + + datetimepicker.data('input').val( _xdsoft_datetime.str() ); + + !options.inline&&datetimepicker.trigger('close.xdsoft'); + + if( options.onSelectTime&&options.onSelectTime.call ) { + options.onSelectTime.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input')); + } + datetimepicker.data('changed',true); + datetimepicker.trigger('xchange.xdsoft'); + datetimepicker.trigger('changedatetime.xdsoft'); + }); + + datetimepicker.mousewheel&&datepicker.mousewheel(function(event, delta, deltaX, deltaY) { + if( !options.scrollMonth ) + return true; + if( delta<0 ) + _xdsoft_datetime.nextMonth(); + else + _xdsoft_datetime.prevMonth(); + return false; + }); + + datetimepicker.mousewheel&&timeboxparent.unmousewheel().mousewheel(function(event, delta, deltaX, deltaY) { + if( !options.scrollTime ) + return true; + var pheight = timeboxparent[0].clientHeight, + height = timebox[0].offsetHeight, + top = Math.abs(parseInt(timebox.css('marginTop'))), + fl = true; + if( delta<0 && (height-pheight)-options.timeHeightInTimePicker>=top ) { + timebox.css('marginTop','-'+(top+options.timeHeightInTimePicker)+'px'); + fl = false; + }else if( delta>0&&top-options.timeHeightInTimePicker>=0 ) { + timebox.css('marginTop','-'+(top-options.timeHeightInTimePicker)+'px'); + fl = false; + } + timeboxparent.trigger('scroll_element.xdsoft_scroller',[Math.abs(parseInt(timebox.css('marginTop'))/(height-pheight))]); + event.stopPropagation(); + return fl; + }); + + var triggerAfterOpen = false; + datetimepicker + .on('changedatetime.xdsoft',function() { + if( options.onChangeDateTime&&options.onChangeDateTime.call ) { + var $input = datetimepicker.data('input'); + options.onChangeDateTime.call(datetimepicker, _xdsoft_datetime.currentTime, $input); + $input.trigger('change'); + } + }) + .on('generate.xdsoft',function() { + if( options.onGenerate&&options.onGenerate.call ) + options.onGenerate.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input')); + if( triggerAfterOpen ){ + datetimepicker.trigger('afterOpen.xdsoft'); + triggerAfterOpen = false; + } + }) + .on( 'click.xdsoft', function( xdevent ) + { + xdevent.stopPropagation(); // Prevents closing of Pop-ups, Modals and Flyouts in Bootstrap + }); + + var current_time_index = 0; + input.mousewheel&&input.mousewheel(function( event, delta, deltaX, deltaY ) { + if( !options.scrollInput ) + return true; + if( !options.datepicker && options.timepicker ) { + current_time_index = timebox.find('.xdsoft_current').length?timebox.find('.xdsoft_current').eq(0).index():0; + if( current_time_index+delta>=0&¤t_time_index+delta$(window).height()+$(window).scrollTop() ) + top = offset.top-datetimepicker[0].offsetHeight+1; + if (top < 0) + top = 0; + if( left+datetimepicker[0].offsetWidth>$(window).width() ) + left = offset.left-datetimepicker[0].offsetWidth+datetimepicker.data('input')[0].offsetWidth; + } + datetimepicker.css({ + left:left, + top:top, + position: position + }); + }; + datetimepicker + .on('open.xdsoft', function() { + var onShow = true; + if( options.onShow&&options.onShow.call) { + onShow = options.onShow.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input')); + } + if( onShow!==false ) { + datetimepicker.show(); + setPos(); + $(window) + .off('resize.xdsoft',setPos) + .on('resize.xdsoft',setPos); + + if( options.closeOnWithoutClick ) { + $([document.body,window]).on('mousedown.xdsoft',function arguments_callee6() { + datetimepicker.trigger('close.xdsoft'); + $([document.body,window]).off('mousedown.xdsoft',arguments_callee6); + }); + } + } + }) + .on('close.xdsoft', function( event ) { + var onClose = true; + if( options.onClose&&options.onClose.call ) { + onClose=options.onClose.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input')); + } + if( onClose!==false&&!options.opened&&!options.inline ) { + datetimepicker.hide(); + } + event.stopPropagation(); + }) + .data('input',input); + + var timer = 0, + timer1 = 0; + + datetimepicker.data('xdsoft_datetime',_xdsoft_datetime); + datetimepicker.setOptions(options); + + function getCurrentValue(){ + var ct = options.value?options.value:(input&&input.val&&input.val())?input.val():''; + + if( ct && _xdsoft_datetime.isValidDate(ct = Date.parseDate(ct, options.format)) ) { + datetimepicker.data('changed',true); + }else + ct = ''; + + if( !ct && options.startDate!==false ){ + ct = _xdsoft_datetime.strToDateTime(options.startDate); + } + + return ct?ct:0; + } + + _xdsoft_datetime.setCurrentTime( getCurrentValue() ); + + input + .data( 'xdsoft_datetimepicker',datetimepicker ) + .on('open.xdsoft focusin.xdsoft mousedown.xdsoft',function(event) { + if( input.is(':disabled')||input.is(':hidden')||!input.is(':visible') ) + return; + clearTimeout(timer); + timer = setTimeout(function() { + if( input.is(':disabled')||input.is(':hidden')||!input.is(':visible') ) + return; + + triggerAfterOpen = true; + _xdsoft_datetime.setCurrentTime(getCurrentValue()); + + datetimepicker.trigger('open.xdsoft'); + },100); + }) + .on('keydown.xdsoft',function( event ) { + var val = this.value, + key = event.which; + switch(true) { + case !!~([ENTER].indexOf(key)): + var elementSelector = $("input:visible,textarea:visible"); + datetimepicker.trigger('close.xdsoft'); + elementSelector.eq(elementSelector.index(this) + 1).focus(); + return false; + case !!~[TAB].indexOf(key): + datetimepicker.trigger('close.xdsoft'); + return true; + } + }); + }, + destroyDateTimePicker = function( input ) { + var datetimepicker = input.data('xdsoft_datetimepicker'); + if( datetimepicker ) { + datetimepicker.data('xdsoft_datetime',null); + datetimepicker.remove(); + input + .data( 'xdsoft_datetimepicker',null ) + .off( 'open.xdsoft focusin.xdsoft focusout.xdsoft mousedown.xdsoft blur.xdsoft keydown.xdsoft' ); + $(window).off('resize.xdsoft'); + $([window,document.body]).off('mousedown.xdsoft'); + input.unmousewheel&&input.unmousewheel(); + } + }; + $(document) + .off('keydown.xdsoftctrl keyup.xdsoftctrl') + .on('keydown.xdsoftctrl',function(e) { + if ( e.keyCode == CTRLKEY ) + ctrlDown = true; + }) + .on('keyup.xdsoftctrl',function(e) { + if ( e.keyCode == CTRLKEY ) + ctrlDown = false; + }); + return this.each(function() { + var datetimepicker; + if( datetimepicker = $(this).data('xdsoft_datetimepicker') ) { + if( $.type(opt) === 'string' ) { + switch(opt) { + case 'show': + $(this).select().focus(); + datetimepicker.trigger( 'open.xdsoft' ); + break; + case 'hide': + datetimepicker.trigger('close.xdsoft'); + break; + case 'destroy': + destroyDateTimePicker($(this)); + break; + case 'reset': + this.value = this.defaultValue; + if(!this.value || !datetimepicker.data('xdsoft_datetime').isValidDate(Date.parseDate(this.value, options.format))) + datetimepicker.data('changed',false); + datetimepicker.data('xdsoft_datetime').setCurrentTime(this.value); + break; + } + }else{ + datetimepicker + .setOptions(opt); + } + return 0; + }else + if( ($.type(opt) !== 'string') ){ + if( !options.lazyInit||options.open||options.inline ){ + createDateTimePicker($(this)); + }else + lazyInit($(this)); + } + }); + }; + $.fn.datetimepicker.defaults = default_options; +})( jQuery ); + +/* + * Copyright (c) 2013 Brandon Aaron (http://brandonaaron.net) + * + * Licensed under the MIT License (LICENSE.txt). + * + * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. + * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. + * Thanks to: Seamus Leahy for adding deltaX and deltaY + * + * Version: 3.1.3 + * + * Requires: 1.2.2+ + */ +(function(factory) {if(typeof define==='function'&&define.amd) {define(['jquery'],factory)}else if(typeof exports==='object') {module.exports=factory}else{factory(jQuery)}}(function($) {var toFix=['wheel','mousewheel','DOMMouseScroll','MozMousePixelScroll'];var toBind='onwheel'in document||document.documentMode>=9?['wheel']:['mousewheel','DomMouseScroll','MozMousePixelScroll'];var lowestDelta,lowestDeltaXY;if($.event.fixHooks) {for(var i=toFix.length;i;) {$.event.fixHooks[toFix[--i]]=$.event.mouseHooks}}$.event.special.mousewheel={setup:function() {if(this.addEventListener) {for(var i=toBind.length;i;) {this.addEventListener(toBind[--i],handler,false)}}else{this.onmousewheel=handler}},teardown:function() {if(this.removeEventListener) {for(var i=toBind.length;i;) {this.removeEventListener(toBind[--i],handler,false)}}else{this.onmousewheel=null}}};$.fn.extend({mousewheel:function(fn) {return fn?this.bind("mousewheel",fn):this.trigger("mousewheel")},unmousewheel:function(fn) {return this.unbind("mousewheel",fn)}});function handler(event) {var orgEvent=event||window.event,args=[].slice.call(arguments,1),delta=0,deltaX=0,deltaY=0,absDelta=0,absDeltaXY=0,fn;event=$.event.fix(orgEvent);event.type="mousewheel";if(orgEvent.wheelDelta) {delta=orgEvent.wheelDelta}if(orgEvent.detail) {delta=orgEvent.detail*-1}if(orgEvent.deltaY) {deltaY=orgEvent.deltaY*-1;delta=deltaY}if(orgEvent.deltaX) {deltaX=orgEvent.deltaX;delta=deltaX*-1}if(orgEvent.wheelDeltaY!==undefined) {deltaY=orgEvent.wheelDeltaY}if(orgEvent.wheelDeltaX!==undefined) {deltaX=orgEvent.wheelDeltaX*-1}absDelta=Math.abs(delta);if(!lowestDelta||absDelta0?'floor':'ceil';delta=Math[fn](delta/lowestDelta);deltaX=Math[fn](deltaX/lowestDeltaXY);deltaY=Math[fn](deltaY/lowestDeltaXY);args.unshift(event,delta,deltaX,deltaY);return($.event.dispatch||$.event.handle).apply(this,args)}})); + + +// Parse and Format Library +//http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/ +/* + * Copyright (C) 2004 Baron Schwartz + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, version 2.1. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + */ +Date.parseFunctions={count:0};Date.parseRegexes=[];Date.formatFunctions={count:0};Date.prototype.dateFormat=function(b){if(b=="unixtime"){return parseInt(this.getTime()/1000);}if(Date.formatFunctions[b]==null){Date.createNewFormat(b);}var a=Date.formatFunctions[b];return this[a]();};Date.createNewFormat=function(format){var funcName="format"+Date.formatFunctions.count++;Date.formatFunctions[format]=funcName;var code="Date.prototype."+funcName+" = function() {return ";var special=false;var ch="";for(var i=0;i 0) {";var regex="";var special=false;var ch="";for(var i=0;i 0 && z > 0){\nvar doyDate = new Date(y,0);\ndoyDate.setDate(z);\nm = doyDate.getMonth();\nd = doyDate.getDate();\n}";code+="if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n{return new Date(y, m, d, h, i, s);}\nelse if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n{return new Date(y, m, d, h, i);}\nelse if (y > 0 && m >= 0 && d > 0 && h >= 0)\n{return new Date(y, m, d, h);}\nelse if (y > 0 && m >= 0 && d > 0)\n{return new Date(y, m, d);}\nelse if (y > 0 && m >= 0)\n{return new Date(y, m);}\nelse if (y > 0)\n{return new Date(y);}\n}return null;}";Date.parseRegexes[regexNum]=new RegExp("^"+regex+"$");eval(code);};Date.formatCodeToRegex=function(b,a){switch(b){case"D":return{g:0,c:null,s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};case"j":case"d":return{g:1,c:"d = parseInt(results["+a+"], 10);\n",s:"(\\d{1,2})"};case"l":return{g:0,c:null,s:"(?:"+Date.dayNames.join("|")+")"};case"S":return{g:0,c:null,s:"(?:st|nd|rd|th)"};case"w":return{g:0,c:null,s:"\\d"};case"z":return{g:1,c:"z = parseInt(results["+a+"], 10);\n",s:"(\\d{1,3})"};case"W":return{g:0,c:null,s:"(?:\\d{2})"};case"F":return{g:1,c:"m = parseInt(Date.monthNumbers[results["+a+"].substring(0, 3)], 10);\n",s:"("+Date.monthNames.join("|")+")"};case"M":return{g:1,c:"m = parseInt(Date.monthNumbers[results["+a+"]], 10);\n",s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};case"n":case"m":return{g:1,c:"m = parseInt(results["+a+"], 10) - 1;\n",s:"(\\d{1,2})"};case"t":return{g:0,c:null,s:"\\d{1,2}"};case"L":return{g:0,c:null,s:"(?:1|0)"};case"Y":return{g:1,c:"y = parseInt(results["+a+"], 10);\n",s:"(\\d{4})"};case"y":return{g:1,c:"var ty = parseInt(results["+a+"], 10);\ny = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",s:"(\\d{1,2})"};case"a":return{g:1,c:"if (results["+a+"] == 'am') {\nif (h == 12) { h = 0; }\n} else { if (h < 12) { h += 12; }}",s:"(am|pm)"};case"A":return{g:1,c:"if (results["+a+"] == 'AM') {\nif (h == 12) { h = 0; }\n} else { if (h < 12) { h += 12; }}",s:"(AM|PM)"};case"g":case"G":case"h":case"H":return{g:1,c:"h = parseInt(results["+a+"], 10);\n",s:"(\\d{1,2})"};case"i":return{g:1,c:"i = parseInt(results["+a+"], 10);\n",s:"(\\d{2})"};case"s":return{g:1,c:"s = parseInt(results["+a+"], 10);\n",s:"(\\d{2})"};case"O":return{g:0,c:null,s:"[+-]\\d{4}"};case"T":return{g:0,c:null,s:"[A-Z]{3}"};case"Z":return{g:0,c:null,s:"[+-]\\d{1,5}"};default:return{g:0,c:null,s:String.escape(b)};}};Date.prototype.getTimezone=function(){return this.toString().replace(/^.*? ([A-Z]{3}) [0-9]{4}.*$/,"$1").replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/,"$1$2$3");};Date.prototype.getGMTOffset=function(){return(this.getTimezoneOffset()>0?"-":"+")+String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset())/60),2,"0")+String.leftPad(Math.abs(this.getTimezoneOffset())%60,2,"0");};Date.prototype.getDayOfYear=function(){var a=0;Date.daysInMonth[1]=this.isLeapYear()?29:28;for(var b=0;bdiv >div{ + background: #F5F5F5; + border-top:1px solid #DDDDDD; + color: #666666; + font-size: 12px; + text-align: center; + border-collapse:collapse; + cursor:pointer; + border-bottom-width:0px; + height:25px; + line-height:25px; +} + +.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div > div:first-child{ + border-top-width:0px; +} +.xdsoft_datetimepicker .xdsoft_today_button:hover, +.xdsoft_datetimepicker .xdsoft_next:hover, +.xdsoft_datetimepicker .xdsoft_prev:hover { + opacity: 1; +} +.xdsoft_datetimepicker .xdsoft_label{ + display: inline; + position: relative; + z-index: 9999; + margin: 0; + padding: 5px 3px; + font-size: 14px; + line-height: 20px; + font-weight: bold; + background-color: #fff; + float:left; + width:182px; + text-align:center; + cursor:pointer; +} +.xdsoft_datetimepicker .xdsoft_label:hover{ + text-decoration:underline; +} +.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select{ + border:1px solid #ccc; + position:absolute; + display:block; + right:0px; + top:30px; + z-index:101; + display:none; + background:#fff; + max-height:160px; + overflow-y:hidden; +} +.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select.xdsoft_monthselect{right:-7px;} +.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select.xdsoft_yearselect{right:2px;} +.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option:hover{ + color: #fff; + background: #ff8000; +} +.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option{ + padding:2px 10px 2px 5px; +} +.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option.xdsoft_current{ + background: #33AAFF; + box-shadow: #178FE5 0px 1px 3px 0px inset; + color:#fff; + font-weight: 700; +} +.xdsoft_datetimepicker .xdsoft_month{ + width:90px; + text-align:right; +} +.xdsoft_datetimepicker .xdsoft_calendar{ + clear:both; +} +.xdsoft_datetimepicker .xdsoft_year{ + width:56px; +} +.xdsoft_datetimepicker .xdsoft_calendar table{ + border-collapse:collapse; + width:100%; + +} +.xdsoft_datetimepicker .xdsoft_calendar td > div{ + padding-right:5px; +} +.xdsoft_datetimepicker .xdsoft_calendar th{ + height: 25px; +} +.xdsoft_datetimepicker .xdsoft_calendar td,.xdsoft_datetimepicker .xdsoft_calendar th{ + width:14.2857142%; + text-align:center; + background: #F5F5F5; + border:1px solid #DDDDDD; + color: #666666; + font-size: 12px; + text-align: right; + padding:0px; + border-collapse:collapse; + cursor:pointer; + height: 25px; +} +.xdsoft_datetimepicker .xdsoft_calendar th{ + background: #F1F1F1; +} +.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_today{ + color:#33AAFF; +} +.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_default, +.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current, +.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_current{ + background: #33AAFF; + box-shadow: #178FE5 0px 1px 3px 0px inset; + color:#fff; + font-weight: 700; +} +.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month, +.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled, +.xdsoft_datetimepicker .xdsoft_time_box >div >div.xdsoft_disabled{ + opacity:0.5; +} +.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month.xdsoft_disabled{ + opacity:0.2; +} +.xdsoft_datetimepicker .xdsoft_calendar td:hover, +.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div:hover{ + color: #fff !important; + background: #ff8000 !important; + box-shadow: none !important; +} +.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled:hover, +.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_disabled:hover{ + color: inherit !important; + background: inherit !important; + box-shadow: inherit !important; +} +.xdsoft_datetimepicker .xdsoft_calendar th{ + font-weight: 700; + text-align: center; + color: #999; + cursor:default; +} +.xdsoft_datetimepicker .xdsoft_copyright{ color:#ccc !important; font-size:10px;clear:both;float:none;margin-left:8px;} +.xdsoft_datetimepicker .xdsoft_copyright a{ color:#eee !important;} +.xdsoft_datetimepicker .xdsoft_copyright a:hover{ color:#aaa !important;} + + +.xdsoft_time_box{ + position:relative; + border:1px solid #ccc; +} +.xdsoft_scrollbar >.xdsoft_scroller{ + background:#ccc !important; + height:20px; + border-radius:3px; +} +.xdsoft_scrollbar{ + position:absolute; + width:7px; + width:7px; + right:0px; + top:0px; + bottom:0px; + cursor:pointer; +} +.xdsoft_scroller_box{ +position:relative; +} \ No newline at end of file diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html b/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html index 30256781ee5..f6226e0a85a 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html @@ -5,6 +5,7 @@ {% compress css %} + {% endcompress %} @@ -17,6 +18,7 @@ + From 614b49213dece2fd6a429bf9bea129ceaa96d193 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 15:04:28 +0100 Subject: [PATCH 043/293] Swapped out jQueryUI datetimepicker for xdsoft datetimepicker --- wagtail/wagtailadmin/edit_handlers.py | 129 +----------------- .../static/wagtailadmin/js/page-editor.js | 59 ++------ .../wagtailforms/index_submissions.html | 27 ++-- 3 files changed, 24 insertions(+), 191 deletions(-) diff --git a/wagtail/wagtailadmin/edit_handlers.py b/wagtail/wagtailadmin/edit_handlers.py index 245f7ad60d1..2b4006610e0 100644 --- a/wagtail/wagtailadmin/edit_handlers.py +++ b/wagtail/wagtailadmin/edit_handlers.py @@ -23,133 +23,12 @@ from wagtail.wagtailcore.fields import RichTextArea -class FriendlyDateInput(forms.DateInput): - """ - A custom DateInput widget that formats dates as "05 Oct 2013" - and adds class="friendly_date" to be picked up by jquery datepicker. - """ - def __init__(self, attrs=None): - default_attrs = {'class': 'friendly_date'} - if attrs: - default_attrs.update(attrs) - - super(FriendlyDateInput, self).__init__(attrs=default_attrs, format='%d %b %Y') - - -class FriendlyTimeInput(forms.TimeInput): - """ - A custom TimeInput widget that formats dates as "5.30pm" - and adds class="friendly_time" to be picked up by jquery timepicker. - """ - def __init__(self, attrs=None): - default_attrs = {'class': 'friendly_time'} - if attrs: - default_attrs.update(attrs) - - super(FriendlyTimeInput, self).__init__(attrs=default_attrs, format='%I.%M%p') - - -class FriendlyTimeField(forms.CharField): - def to_python(self, time_string): - # Check if the string is blank - if not time_string: - return None - - # Look for time in the string - expr = re.compile("^(?P\d+)(?:(?:.|:)(?P\d+))?(?Pam|pm)") - match = expr.match(time_string.lower()) - if match: - # Pull out values from string - hour_string, minute_string, am_pm = match.groups() - - # Convert hours and minutes to integers - hour = int(hour_string) - if minute_string: - minute = int(minute_string) - else: - minute = 0 - - # Create python time - if am_pm == "pm" and hour < 12: - hour += 12 - - if am_pm == "am" and hour >= 12: - hour -= 12 - - return datetime.time(hour=hour, minute=minute) - else: - raise ValidationError(_("Please type a valid time")) - - -class LocalizedDateInput(forms.DateInput): - """ - A custom DateInput widget that formats localized dates - and adds class="friendly_date" to be picked up by jquery datepicker. - """ - def __init__(self, attrs=None): - default_attrs = {'class': 'localized_date', 'localize':True} - if attrs: - default_attrs.update(attrs) - - super(LocalizedDateInput, self).__init__(attrs=default_attrs) - - -class LocalizedTimeInput(forms.TimeInput): - """ - A custom TimeInput widget that formats dates as "5.30pm" - and adds class="friendly_time" to be picked up by jquery timepicker. - """ - def __init__(self, attrs=None): - default_attrs = {'class': 'localized_time'} - if attrs: - default_attrs.update(attrs) - # Just use 24-hour format - super(LocalizedTimeInput, self).__init__(attrs=default_attrs, format='%H:%M') - - -class LocalizedTimeField(forms.CharField): - def to_python(self, time_string): - # Check if the string is blank - if not time_string: - return None - - # Look for time in the string - expr = re.compile("^(?P\d+)(?:(?:.|:)(?P\d+))?") - match = expr.match(time_string.lower()) - if match: - # Pull out values from string - hour_string, minute_string= match.groups() - - # Convert hours and minutes to integers - hour = int(hour_string) - if minute_string: - minute = int(minute_string) - else: - minute = 0 - if hour>=24 or hour < 0 or minute >=60 or minute < 0: - raise ValidationError(_("Please type a valid time")) - - return datetime.time(hour=hour, minute=minute) - else: - raise ValidationError(_("Please type a valid time") ) - - -if hasattr(settings, 'USE_L10N') and settings.USE_L10N==True: - FORM_FIELD_OVERRIDES = { - models.DateField: {'widget': LocalizedDateInput}, - models.TimeField: {'widget': LocalizedTimeInput, 'form_class': LocalizedTimeField}, - } -else: # Fall back to friendly date/time - FORM_FIELD_OVERRIDES = { - models.DateField: {'widget': FriendlyDateInput}, - models.TimeField: {'widget': FriendlyTimeInput, 'form_class': FriendlyTimeField}, - } +FORM_FIELD_OVERRIDES = {} WIDGET_JS = { - FriendlyDateInput: (lambda id: "initFriendlyDateChooser(fixPrefix('%s'));" % id), - FriendlyTimeInput: (lambda id: "initFriendlyTimeChooser(fixPrefix('%s'));" % id), - LocalizedDateInput: (lambda id: "initLocalizedDateChooser(fixPrefix('%s'));" % id), - LocalizedTimeInput: (lambda id: "initLocalizedTimeChooser(fixPrefix('%s'));" % id), + forms.DateInput: (lambda id: "initDateChooser(fixPrefix('%s'));" % id), + forms.TimeInput: (lambda id: "initTimeChooser(fixPrefix('%s'));" % id), + forms.DateTimeInput: (lambda id: "initDateTimeChooser(fixPrefix('%s'));" % id), RichTextArea: (lambda id: "makeRichTextEditable(fixPrefix('%s'));" % id), TagWidget: ( lambda id: "initTagField(fixPrefix('%s'), '%s');" % ( diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js index cbff2c8af8a..a8d492ffc52 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js +++ b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js @@ -53,56 +53,23 @@ function insertRichTextDeleteControl(elem) { }); } -function initDateChoosers(context) { - $('input.friendly_date', context).datepicker({ - dateFormat: 'd M yy', constrainInput: false, /* showOn: 'button', */ firstDay: 1 +function initDateChooser(id) { + $('#' + id).datetimepicker({ + timepicker: false, + format: 'Y-m-d' }); - - if(window.overrideDateInputFormat && window.overrideDateInputFormat !='') { - $('input.localized_date', context).datepicker({ - dateFormat: window.overrideDateInputFormat, constrainInput: false, /* showOn: 'button', */ firstDay: 1 - }); - } else { - $('input.localized_date', context).datepicker({ - constrainInput: false, /* showOn: 'button', */ firstDay: 1 - }); - } - -} -function initFriendlyDateChooser(id) { - $('#' + id).datepicker({ - dateFormat: 'd M yy', constrainInput: false, /* showOn: 'button', */ firstDay: 1 - }); -} -function initLocalizedDateChooser(id) { - if(window.overrideDateInputFormat && window.overrideDateInputFormat !='') { - $('#' + id).datepicker({ - dateFormat: window.overrideDateInputFormat, constrainInput: false, /* showOn: 'button', */ firstDay: 1 - }); - } else { - $('#' + id).datepicker({ - constrainInput: false, /* showOn: 'button', */ firstDay: 1 - }); - } - } -function initTimeChoosers(context) { - $('input.friendly_time', context).timepicker({ - timeFormat: 'g.ia' - }); - $('input.localized_time', context).timepicker({ - timeFormat: 'H:i', maxTime: '23:59' - }); -} -function initFriendlyTimeChooser(id) { - $('#' + id).timepicker({ - timeFormat: 'g.ia' +function initTimeChooser(id) { + $('#' + id).datetimepicker({ + datepicker: false, + format: 'H:i' }); } -function initLocalizedTimeChooser(id) { - $('#' + id).timepicker({ - timeFormat: 'H:i', maxTime: '23:59' + +function initDateTimeChooser(id) { + $('#' + id).datetimepicker({ + format: 'Y-m-d H:i' }); } @@ -309,8 +276,6 @@ function initCollapsibleBlocks(){ } $(function() { - initDateChoosers(); - initTimeChoosers(); initSlugAutoPopulate(); initSlugCleaning(); initErrorDetection(); diff --git a/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html b/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html index a1b45f6d0fb..00732ee4187 100644 --- a/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html +++ b/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html @@ -4,27 +4,16 @@ {% block titletag %}{% blocktrans with form_title=form_page.title|capfirst %}Submissions of {{ form_title }}{% endblocktrans %}{% endblock %} {% block bodyclass %}menu-snippets{% endblock %} {% block extra_js %} - {% get_localized_datepicker_js %} - {% get_date_format_override as format_override %} - {% endblock %} From 99a70b3d9d0df6d5f96a4b2c93aba8cfca4c9a73 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 15:06:41 +0100 Subject: [PATCH 044/293] Removed jQueryUI datetimepicker --- .../js/vendor/i18n/jquery.ui.datepicker-af.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-ar-DZ.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-ar.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-az.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-be.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-bg.js | 24 ------- .../js/vendor/i18n/jquery.ui.datepicker-bs.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-ca.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-cs.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-cy-GB.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-da.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-de.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-el.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-en-AU.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-en-GB.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-en-NZ.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-eo.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-es.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-et.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-eu.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-fa.js | 59 ---------------- .../js/vendor/i18n/jquery.ui.datepicker-fi.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-fo.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-fr-CA.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-fr-CH.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-fr.js | 25 ------- .../js/vendor/i18n/jquery.ui.datepicker-gl.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-he.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-hi.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-hr.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-hu.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-hy.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-id.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-is.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-it.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-ja.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-ka.js | 21 ------ .../js/vendor/i18n/jquery.ui.datepicker-kk.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-km.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-ko.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-ky.js | 24 ------- .../js/vendor/i18n/jquery.ui.datepicker-lb.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-lt.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-lv.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-mk.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-ml.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-ms.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-nb.js | 22 ------ .../vendor/i18n/jquery.ui.datepicker-nl-BE.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-nl.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-nn.js | 22 ------ .../js/vendor/i18n/jquery.ui.datepicker-no.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-pl.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-pt-BR.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-pt.js | 22 ------ .../js/vendor/i18n/jquery.ui.datepicker-rm.js | 21 ------ .../js/vendor/i18n/jquery.ui.datepicker-ro.js | 26 ------- .../js/vendor/i18n/jquery.ui.datepicker-ru.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-sk.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-sl.js | 24 ------- .../js/vendor/i18n/jquery.ui.datepicker-sq.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-sr-SR.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-sr.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-sv.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-ta.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-th.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-tj.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-tr.js | 23 ------- .../js/vendor/i18n/jquery.ui.datepicker-uk.js | 24 ------- .../js/vendor/i18n/jquery.ui.datepicker-vi.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-zh-CN.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-zh-HK.js | 23 ------- .../vendor/i18n/jquery.ui.datepicker-zh-TW.js | 23 ------- .../js/vendor/jquery.timepicker.min.js | 1 - .../scss/vendor/jquery.timepicker.css | 67 ------------------- .../templates/wagtailadmin/admin_base.html | 2 - .../wagtailadmin/pages/_editor_js.html | 8 --- wagtail/wagtailadmin/templatetags/localize.py | 62 ----------------- 78 files changed, 1857 deletions(-) delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-af.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ar-DZ.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ar.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-az.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-be.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-bg.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-bs.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ca.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-cs.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-cy-GB.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-da.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-de.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-el.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-AU.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-GB.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-NZ.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-eo.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-es.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-et.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-eu.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fa.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fi.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fo.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr-CA.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr-CH.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-gl.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-he.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hi.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hr.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hu.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hy.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-id.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-is.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-it.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ja.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ka.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-kk.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-km.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ko.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ky.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lb.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lt.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lv.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-mk.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ml.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ms.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nb.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nl-BE.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nl.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nn.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-no.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pl.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pt-BR.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pt.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-rm.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ro.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ru.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sk.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sl.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sq.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sr-SR.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sr.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sv.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ta.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-th.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-tj.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-tr.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-uk.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-vi.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-CN.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-HK.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-TW.js delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/js/vendor/jquery.timepicker.min.js delete mode 100755 wagtail/wagtailadmin/static/wagtailadmin/scss/vendor/jquery.timepicker.css delete mode 100644 wagtail/wagtailadmin/templatetags/localize.py diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-af.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-af.js deleted file mode 100644 index 0922ef7a1c0..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-af.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Afrikaans initialisation for the jQuery UI date picker plugin. */ -/* Written by Renier Pretorius. */ -jQuery(function($){ - $.datepicker.regional['af'] = { - closeText: 'Selekteer', - prevText: 'Vorige', - nextText: 'Volgende', - currentText: 'Vandag', - monthNames: ['Januarie','Februarie','Maart','April','Mei','Junie', - 'Julie','Augustus','September','Oktober','November','Desember'], - monthNamesShort: ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', - 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'], - dayNames: ['Sondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrydag', 'Saterdag'], - dayNamesShort: ['Son', 'Maa', 'Din', 'Woe', 'Don', 'Vry', 'Sat'], - dayNamesMin: ['So','Ma','Di','Wo','Do','Vr','Sa'], - weekHeader: 'Wk', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['af']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ar-DZ.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ar-DZ.js deleted file mode 100644 index 7b175af40ea..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ar-DZ.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Algerian Arabic Translation for jQuery UI date picker plugin. (can be used for Tunisia)*/ -/* Mohamed Cherif BOUCHELAGHEM -- cherifbouchelaghem@yahoo.fr */ - -jQuery(function($){ - $.datepicker.regional['ar-DZ'] = { - closeText: 'إغلاق', - prevText: '<السابق', - nextText: 'التالي>', - currentText: 'اليوم', - monthNames: ['جانفي', 'فيفري', 'مارس', 'أفريل', 'ماي', 'جوان', - 'جويلية', 'أوت', 'سبتمبر','أكتوبر', 'نوفمبر', 'ديسمبر'], - monthNamesShort: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], - dayNames: ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'], - dayNamesShort: ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'], - dayNamesMin: ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'], - weekHeader: 'أسبوع', - dateFormat: 'dd/mm/yy', - firstDay: 6, - isRTL: true, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['ar-DZ']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ar.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ar.js deleted file mode 100644 index cef0f08fd2d..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ar.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Arabic Translation for jQuery UI date picker plugin. */ -/* Khaled Alhourani -- me@khaledalhourani.com */ -/* NOTE: monthNames are the original months names and they are the Arabic names, not the new months name فبراير - يناير and there isn't any Arabic roots for these months */ -jQuery(function($){ - $.datepicker.regional['ar'] = { - closeText: 'إغلاق', - prevText: '<السابق', - nextText: 'التالي>', - currentText: 'اليوم', - monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'مايو', 'حزيران', - 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'], - monthNamesShort: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], - dayNames: ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'], - dayNamesShort: ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'], - dayNamesMin: ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'], - weekHeader: 'أسبوع', - dateFormat: 'dd/mm/yy', - firstDay: 6, - isRTL: true, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['ar']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-az.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-az.js deleted file mode 100644 index a133a9eb234..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-az.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Azerbaijani (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* Written by Jamil Najafov (necefov33@gmail.com). */ -jQuery(function($) { - $.datepicker.regional['az'] = { - closeText: 'Bağla', - prevText: '<Geri', - nextText: 'İrəli>', - currentText: 'Bugün', - monthNames: ['Yanvar','Fevral','Mart','Aprel','May','İyun', - 'İyul','Avqust','Sentyabr','Oktyabr','Noyabr','Dekabr'], - monthNamesShort: ['Yan','Fev','Mar','Apr','May','İyun', - 'İyul','Avq','Sen','Okt','Noy','Dek'], - dayNames: ['Bazar','Bazar ertəsi','Çərşənbə axşamı','Çərşənbə','Cümə axşamı','Cümə','Şənbə'], - dayNamesShort: ['B','Be','Ça','Ç','Ca','C','Ş'], - dayNamesMin: ['B','B','Ç','С','Ç','C','Ş'], - weekHeader: 'Hf', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['az']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-be.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-be.js deleted file mode 100644 index 6ea12f72561..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-be.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Belarusian initialisation for the jQuery UI date picker plugin. */ -/* Written by Pavel Selitskas */ -jQuery(function($){ - $.datepicker.regional['be'] = { - closeText: 'Зачыніць', - prevText: '←Папяр.', - nextText: 'Наст.→', - currentText: 'Сёньня', - monthNames: ['Студзень','Люты','Сакавік','Красавік','Травень','Чэрвень', - 'Ліпень','Жнівень','Верасень','Кастрычнік','Лістапад','Сьнежань'], - monthNamesShort: ['Сту','Лют','Сак','Кра','Тра','Чэр', - 'Ліп','Жні','Вер','Кас','Ліс','Сьн'], - dayNames: ['нядзеля','панядзелак','аўторак','серада','чацьвер','пятніца','субота'], - dayNamesShort: ['ндз','пнд','аўт','срд','чцв','птн','сбт'], - dayNamesMin: ['Нд','Пн','Аў','Ср','Чц','Пт','Сб'], - weekHeader: 'Тд', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['be']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-bg.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-bg.js deleted file mode 100644 index 86ab885828b..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-bg.js +++ /dev/null @@ -1,24 +0,0 @@ -/* Bulgarian initialisation for the jQuery UI date picker plugin. */ -/* Written by Stoyan Kyosev (http://svest.org). */ -jQuery(function($){ - $.datepicker.regional['bg'] = { - closeText: 'затвори', - prevText: '<назад', - nextText: 'напред>', - nextBigText: '>>', - currentText: 'днес', - monthNames: ['Януари','Февруари','Март','Април','Май','Юни', - 'Юли','Август','Септември','Октомври','Ноември','Декември'], - monthNamesShort: ['Яну','Фев','Мар','Апр','Май','Юни', - 'Юли','Авг','Сеп','Окт','Нов','Дек'], - dayNames: ['Неделя','Понеделник','Вторник','Сряда','Четвъртък','Петък','Събота'], - dayNamesShort: ['Нед','Пон','Вто','Сря','Чет','Пет','Съб'], - dayNamesMin: ['Не','По','Вт','Ср','Че','Пе','Съ'], - weekHeader: 'Wk', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['bg']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-bs.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-bs.js deleted file mode 100644 index f08870ffe36..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-bs.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Bosnian i18n for the jQuery UI date picker plugin. */ -/* Written by Kenan Konjo. */ -jQuery(function($){ - $.datepicker.regional['bs'] = { - closeText: 'Zatvori', - prevText: '<', - nextText: '>', - currentText: 'Danas', - monthNames: ['Januar','Februar','Mart','April','Maj','Juni', - 'Juli','August','Septembar','Oktobar','Novembar','Decembar'], - monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', - 'Jul','Aug','Sep','Okt','Nov','Dec'], - dayNames: ['Nedelja','Ponedeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'], - dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'], - dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], - weekHeader: 'Wk', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['bs']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ca.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ca.js deleted file mode 100644 index a10b549c28c..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ca.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Inicialització en català per a l'extensió 'UI date picker' per jQuery. */ -/* Writers: (joan.leon@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['ca'] = { - closeText: 'Tanca', - prevText: 'Anterior', - nextText: 'Següent', - currentText: 'Avui', - monthNames: ['gener','febrer','març','abril','maig','juny', - 'juliol','agost','setembre','octubre','novembre','desembre'], - monthNamesShort: ['gen','feb','març','abr','maig','juny', - 'jul','ag','set','oct','nov','des'], - dayNames: ['diumenge','dilluns','dimarts','dimecres','dijous','divendres','dissabte'], - dayNamesShort: ['dg','dl','dt','dc','dj','dv','ds'], - dayNamesMin: ['dg','dl','dt','dc','dj','dv','ds'], - weekHeader: 'Set', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['ca']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-cs.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-cs.js deleted file mode 100644 index b96b1a51c2d..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-cs.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Czech initialisation for the jQuery UI date picker plugin. */ -/* Written by Tomas Muller (tomas@tomas-muller.net). */ -jQuery(function($){ - $.datepicker.regional['cs'] = { - closeText: 'Zavřít', - prevText: '<Dříve', - nextText: 'Později>', - currentText: 'Nyní', - monthNames: ['leden','únor','březen','duben','květen','červen', - 'červenec','srpen','září','říjen','listopad','prosinec'], - monthNamesShort: ['led','úno','bře','dub','kvě','čer', - 'čvc','srp','zář','říj','lis','pro'], - dayNames: ['neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota'], - dayNamesShort: ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'], - dayNamesMin: ['ne','po','út','st','čt','pá','so'], - weekHeader: 'Týd', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['cs']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-cy-GB.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-cy-GB.js deleted file mode 100644 index cf3a38e6cd3..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-cy-GB.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Welsh/UK initialisation for the jQuery UI date picker plugin. */ -/* Written by William Griffiths. */ -jQuery(function($){ - $.datepicker.regional['cy-GB'] = { - closeText: 'Done', - prevText: 'Prev', - nextText: 'Next', - currentText: 'Today', - monthNames: ['Ionawr','Chwefror','Mawrth','Ebrill','Mai','Mehefin', - 'Gorffennaf','Awst','Medi','Hydref','Tachwedd','Rhagfyr'], - monthNamesShort: ['Ion', 'Chw', 'Maw', 'Ebr', 'Mai', 'Meh', - 'Gor', 'Aws', 'Med', 'Hyd', 'Tac', 'Rha'], - dayNames: ['Dydd Sul', 'Dydd Llun', 'Dydd Mawrth', 'Dydd Mercher', 'Dydd Iau', 'Dydd Gwener', 'Dydd Sadwrn'], - dayNamesShort: ['Sul', 'Llu', 'Maw', 'Mer', 'Iau', 'Gwe', 'Sad'], - dayNamesMin: ['Su','Ll','Ma','Me','Ia','Gw','Sa'], - weekHeader: 'Wy', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['cy-GB']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-da.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-da.js deleted file mode 100644 index 7e42948b344..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-da.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Danish initialisation for the jQuery UI date picker plugin. */ -/* Written by Jan Christensen ( deletestuff@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['da'] = { - closeText: 'Luk', - prevText: '<Forrige', - nextText: 'Næste>', - currentText: 'Idag', - monthNames: ['Januar','Februar','Marts','April','Maj','Juni', - 'Juli','August','September','Oktober','November','December'], - monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', - 'Jul','Aug','Sep','Okt','Nov','Dec'], - dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], - dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], - dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], - weekHeader: 'Uge', - dateFormat: 'dd-mm-yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['da']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-de.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-de.js deleted file mode 100644 index abe75c4e429..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-de.js +++ /dev/null @@ -1,23 +0,0 @@ -/* German initialisation for the jQuery UI date picker plugin. */ -/* Written by Milian Wolff (mail@milianw.de). */ -jQuery(function($){ - $.datepicker.regional['de'] = { - closeText: 'Schließen', - prevText: '<Zurück', - nextText: 'Vor>', - currentText: 'Heute', - monthNames: ['Januar','Februar','März','April','Mai','Juni', - 'Juli','August','September','Oktober','November','Dezember'], - monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun', - 'Jul','Aug','Sep','Okt','Nov','Dez'], - dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'], - dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'], - dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'], - weekHeader: 'KW', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['de']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-el.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-el.js deleted file mode 100644 index 1ac47561a41..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-el.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Greek (el) initialisation for the jQuery UI date picker plugin. */ -/* Written by Alex Cicovic (http://www.alexcicovic.com) */ -jQuery(function($){ - $.datepicker.regional['el'] = { - closeText: 'Κλείσιμο', - prevText: 'Προηγούμενος', - nextText: 'Επόμενος', - currentText: 'Τρέχων Μήνας', - monthNames: ['Ιανουάριος','Φεβρουάριος','Μάρτιος','Απρίλιος','Μάιος','Ιούνιος', - 'Ιούλιος','Αύγουστος','Σεπτέμβριος','Οκτώβριος','Νοέμβριος','Δεκέμβριος'], - monthNamesShort: ['Ιαν','Φεβ','Μαρ','Απρ','Μαι','Ιουν', - 'Ιουλ','Αυγ','Σεπ','Οκτ','Νοε','Δεκ'], - dayNames: ['Κυριακή','Δευτέρα','Τρίτη','Τετάρτη','Πέμπτη','Παρασκευή','Σάββατο'], - dayNamesShort: ['Κυρ','Δευ','Τρι','Τετ','Πεμ','Παρ','Σαβ'], - dayNamesMin: ['Κυ','Δε','Τρ','Τε','Πε','Πα','Σα'], - weekHeader: 'Εβδ', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['el']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-AU.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-AU.js deleted file mode 100644 index c1a1020a140..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-AU.js +++ /dev/null @@ -1,23 +0,0 @@ -/* English/Australia initialisation for the jQuery UI date picker plugin. */ -/* Based on the en-GB initialisation. */ -jQuery(function($){ - $.datepicker.regional['en-AU'] = { - closeText: 'Done', - prevText: 'Prev', - nextText: 'Next', - currentText: 'Today', - monthNames: ['January','February','March','April','May','June', - 'July','August','September','October','November','December'], - monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], - weekHeader: 'Wk', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['en-AU']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-GB.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-GB.js deleted file mode 100644 index 16a096e758a..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-GB.js +++ /dev/null @@ -1,23 +0,0 @@ -/* English/UK initialisation for the jQuery UI date picker plugin. */ -/* Written by Stuart. */ -jQuery(function($){ - $.datepicker.regional['en-GB'] = { - closeText: 'Done', - prevText: 'Prev', - nextText: 'Next', - currentText: 'Today', - monthNames: ['January','February','March','April','May','June', - 'July','August','September','October','November','December'], - monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], - weekHeader: 'Wk', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['en-GB']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-NZ.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-NZ.js deleted file mode 100644 index 7819df05286..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-en-NZ.js +++ /dev/null @@ -1,23 +0,0 @@ -/* English/New Zealand initialisation for the jQuery UI date picker plugin. */ -/* Based on the en-GB initialisation. */ -jQuery(function($){ - $.datepicker.regional['en-NZ'] = { - closeText: 'Done', - prevText: 'Prev', - nextText: 'Next', - currentText: 'Today', - monthNames: ['January','February','March','April','May','June', - 'July','August','September','October','November','December'], - monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], - weekHeader: 'Wk', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['en-NZ']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-eo.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-eo.js deleted file mode 100644 index 39e44fc57c1..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-eo.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Esperanto initialisation for the jQuery UI date picker plugin. */ -/* Written by Olivier M. (olivierweb@ifrance.com). */ -jQuery(function($){ - $.datepicker.regional['eo'] = { - closeText: 'Fermi', - prevText: '<Anta', - nextText: 'Sekv>', - currentText: 'Nuna', - monthNames: ['Januaro','Februaro','Marto','Aprilo','Majo','Junio', - 'Julio','Aŭgusto','Septembro','Oktobro','Novembro','Decembro'], - monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', - 'Jul','Aŭg','Sep','Okt','Nov','Dec'], - dayNames: ['Dimanĉo','Lundo','Mardo','Merkredo','Ĵaŭdo','Vendredo','Sabato'], - dayNamesShort: ['Dim','Lun','Mar','Mer','Ĵaŭ','Ven','Sab'], - dayNamesMin: ['Di','Lu','Ma','Me','Ĵa','Ve','Sa'], - weekHeader: 'Sb', - dateFormat: 'dd/mm/yy', - firstDay: 0, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['eo']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-es.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-es.js deleted file mode 100644 index 97a2d6ead7d..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-es.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Inicialización en español para la extensión 'UI date picker' para jQuery. */ -/* Traducido por Vester (xvester@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['es'] = { - closeText: 'Cerrar', - prevText: '<Ant', - nextText: 'Sig>', - currentText: 'Hoy', - monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', - 'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'], - monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun', - 'Jul','Ago','Sep','Oct','Nov','Dic'], - dayNames: ['Domingo','Lunes','Martes','Miércoles','Jueves','Viernes','Sábado'], - dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'], - dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], - weekHeader: 'Sm', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['es']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-et.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-et.js deleted file mode 100644 index 62cbea8fa86..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-et.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Estonian initialisation for the jQuery UI date picker plugin. */ -/* Written by Mart Sõmermaa (mrts.pydev at gmail com). */ -jQuery(function($){ - $.datepicker.regional['et'] = { - closeText: 'Sulge', - prevText: 'Eelnev', - nextText: 'Järgnev', - currentText: 'Täna', - monthNames: ['Jaanuar','Veebruar','Märts','Aprill','Mai','Juuni', - 'Juuli','August','September','Oktoober','November','Detsember'], - monthNamesShort: ['Jaan', 'Veebr', 'Märts', 'Apr', 'Mai', 'Juuni', - 'Juuli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dets'], - dayNames: ['Pühapäev', 'Esmaspäev', 'Teisipäev', 'Kolmapäev', 'Neljapäev', 'Reede', 'Laupäev'], - dayNamesShort: ['Pühap', 'Esmasp', 'Teisip', 'Kolmap', 'Neljap', 'Reede', 'Laup'], - dayNamesMin: ['P','E','T','K','N','R','L'], - weekHeader: 'näd', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['et']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-eu.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-eu.js deleted file mode 100644 index a71db2c721c..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-eu.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Euskarako oinarria 'UI date picker' jquery-ko extentsioarentzat */ -/* Karrikas-ek itzulia (karrikas@karrikas.com) */ -jQuery(function($){ - $.datepicker.regional['eu'] = { - closeText: 'Egina', - prevText: '<Aur', - nextText: 'Hur>', - currentText: 'Gaur', - monthNames: ['urtarrila','otsaila','martxoa','apirila','maiatza','ekaina', - 'uztaila','abuztua','iraila','urria','azaroa','abendua'], - monthNamesShort: ['urt.','ots.','mar.','api.','mai.','eka.', - 'uzt.','abu.','ira.','urr.','aza.','abe.'], - dayNames: ['igandea','astelehena','asteartea','asteazkena','osteguna','ostirala','larunbata'], - dayNamesShort: ['ig.','al.','ar.','az.','og.','ol.','lr.'], - dayNamesMin: ['ig','al','ar','az','og','ol','lr'], - weekHeader: 'As', - dateFormat: 'yy-mm-dd', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['eu']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fa.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fa.js deleted file mode 100644 index bb957f6d8d0..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fa.js +++ /dev/null @@ -1,59 +0,0 @@ -/* Persian (Farsi) Translation for the jQuery UI date picker plugin. */ -/* Javad Mowlanezhad -- jmowla@gmail.com */ -/* Jalali calendar should supported soon! (Its implemented but I have to test it) */ -jQuery(function($) { - $.datepicker.regional['fa'] = { - closeText: 'بستن', - prevText: '<قبلی', - nextText: 'بعدی>', - currentText: 'امروز', - monthNames: [ - 'فروردين', - 'ارديبهشت', - 'خرداد', - 'تير', - 'مرداد', - 'شهريور', - 'مهر', - 'آبان', - 'آذر', - 'دی', - 'بهمن', - 'اسفند' - ], - monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'], - dayNames: [ - 'يکشنبه', - 'دوشنبه', - 'سه‌شنبه', - 'چهارشنبه', - 'پنجشنبه', - 'جمعه', - 'شنبه' - ], - dayNamesShort: [ - 'ی', - 'د', - 'س', - 'چ', - 'پ', - 'ج', - 'ش' - ], - dayNamesMin: [ - 'ی', - 'د', - 'س', - 'چ', - 'پ', - 'ج', - 'ش' - ], - weekHeader: 'هف', - dateFormat: 'yy/mm/dd', - firstDay: 6, - isRTL: true, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['fa']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fi.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fi.js deleted file mode 100644 index bd6d99498be..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fi.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Finnish initialisation for the jQuery UI date picker plugin. */ -/* Written by Harri Kilpiö (harrikilpio@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['fi'] = { - closeText: 'Sulje', - prevText: '«Edellinen', - nextText: 'Seuraava»', - currentText: 'Tänään', - monthNames: ['Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kesäkuu', - 'Heinäkuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'], - monthNamesShort: ['Tammi','Helmi','Maalis','Huhti','Touko','Kesä', - 'Heinä','Elo','Syys','Loka','Marras','Joulu'], - dayNamesShort: ['Su','Ma','Ti','Ke','To','Pe','La'], - dayNames: ['Sunnuntai','Maanantai','Tiistai','Keskiviikko','Torstai','Perjantai','Lauantai'], - dayNamesMin: ['Su','Ma','Ti','Ke','To','Pe','La'], - weekHeader: 'Vk', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['fi']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fo.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fo.js deleted file mode 100644 index cb0e3def70f..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fo.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Faroese initialisation for the jQuery UI date picker plugin */ -/* Written by Sverri Mohr Olsen, sverrimo@gmail.com */ -jQuery(function($){ - $.datepicker.regional['fo'] = { - closeText: 'Lat aftur', - prevText: '<Fyrra', - nextText: 'Næsta>', - currentText: 'Í dag', - monthNames: ['Januar','Februar','Mars','Apríl','Mei','Juni', - 'Juli','August','September','Oktober','November','Desember'], - monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun', - 'Jul','Aug','Sep','Okt','Nov','Des'], - dayNames: ['Sunnudagur','Mánadagur','Týsdagur','Mikudagur','Hósdagur','Fríggjadagur','Leyardagur'], - dayNamesShort: ['Sun','Mán','Týs','Mik','Hós','Frí','Ley'], - dayNamesMin: ['Su','Má','Tý','Mi','Hó','Fr','Le'], - weekHeader: 'Vk', - dateFormat: 'dd-mm-yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['fo']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr-CA.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr-CA.js deleted file mode 100644 index e2082218540..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr-CA.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Canadian-French initialisation for the jQuery UI date picker plugin. */ -jQuery(function ($) { - $.datepicker.regional['fr-CA'] = { - closeText: 'Fermer', - prevText: 'Précédent', - nextText: 'Suivant', - currentText: 'Aujourd\'hui', - monthNames: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', - 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'], - monthNamesShort: ['janv.', 'févr.', 'mars', 'avril', 'mai', 'juin', - 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'], - dayNames: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'], - dayNamesShort: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'], - dayNamesMin: ['D', 'L', 'M', 'M', 'J', 'V', 'S'], - weekHeader: 'Sem.', - dateFormat: 'yy-mm-dd', - firstDay: 0, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: '' - }; - $.datepicker.setDefaults($.datepicker.regional['fr-CA']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr-CH.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr-CH.js deleted file mode 100644 index e574537b051..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr-CH.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Swiss-French initialisation for the jQuery UI date picker plugin. */ -/* Written Martin Voelkle (martin.voelkle@e-tc.ch). */ -jQuery(function($){ - $.datepicker.regional['fr-CH'] = { - closeText: 'Fermer', - prevText: '<Préc', - nextText: 'Suiv>', - currentText: 'Courant', - monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin', - 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], - monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun', - 'Jul','Aoû','Sep','Oct','Nov','Déc'], - dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], - dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'], - dayNamesMin: ['Di','Lu','Ma','Me','Je','Ve','Sa'], - weekHeader: 'Sm', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['fr-CH']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr.js deleted file mode 100644 index 934afd1d023..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-fr.js +++ /dev/null @@ -1,25 +0,0 @@ -/* French initialisation for the jQuery UI date picker plugin. */ -/* Written by Keith Wood (kbwood{at}iinet.com.au), - Stéphane Nahmani (sholby@sholby.net), - Stéphane Raimbault */ -jQuery(function($){ - $.datepicker.regional['fr'] = { - closeText: 'Fermer', - prevText: 'Précédent', - nextText: 'Suivant', - currentText: 'Aujourd\'hui', - monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin', - 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], - monthNamesShort: ['Janv.','Févr.','Mars','Avril','Mai','Juin', - 'Juil.','Août','Sept.','Oct.','Nov.','Déc.'], - dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], - dayNamesShort: ['Dim.','Lun.','Mar.','Mer.','Jeu.','Ven.','Sam.'], - dayNamesMin: ['D','L','M','M','J','V','S'], - weekHeader: 'Sem.', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['fr']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-gl.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-gl.js deleted file mode 100644 index 59b989a6dd4..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-gl.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Galician localization for 'UI date picker' jQuery extension. */ -/* Translated by Jorge Barreiro . */ -jQuery(function($){ - $.datepicker.regional['gl'] = { - closeText: 'Pechar', - prevText: '<Ant', - nextText: 'Seg>', - currentText: 'Hoxe', - monthNames: ['Xaneiro','Febreiro','Marzo','Abril','Maio','Xuño', - 'Xullo','Agosto','Setembro','Outubro','Novembro','Decembro'], - monthNamesShort: ['Xan','Feb','Mar','Abr','Mai','Xuñ', - 'Xul','Ago','Set','Out','Nov','Dec'], - dayNames: ['Domingo','Luns','Martes','Mércores','Xoves','Venres','Sábado'], - dayNamesShort: ['Dom','Lun','Mar','Mér','Xov','Ven','Sáb'], - dayNamesMin: ['Do','Lu','Ma','Mé','Xo','Ve','Sá'], - weekHeader: 'Sm', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['gl']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-he.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-he.js deleted file mode 100644 index b9e8deec5fd..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-he.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Hebrew initialisation for the UI Datepicker extension. */ -/* Written by Amir Hardon (ahardon at gmail dot com). */ -jQuery(function($){ - $.datepicker.regional['he'] = { - closeText: 'סגור', - prevText: '<הקודם', - nextText: 'הבא>', - currentText: 'היום', - monthNames: ['ינואר','פברואר','מרץ','אפריל','מאי','יוני', - 'יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'], - monthNamesShort: ['ינו','פבר','מרץ','אפר','מאי','יוני', - 'יולי','אוג','ספט','אוק','נוב','דצמ'], - dayNames: ['ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת'], - dayNamesShort: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], - dayNamesMin: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], - weekHeader: 'Wk', - dateFormat: 'dd/mm/yy', - firstDay: 0, - isRTL: true, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['he']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hi.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hi.js deleted file mode 100644 index 6c563b99751..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hi.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Hindi initialisation for the jQuery UI date picker plugin. */ -/* Written by Michael Dawart. */ -jQuery(function($){ - $.datepicker.regional['hi'] = { - closeText: 'बंद', - prevText: 'पिछला', - nextText: 'अगला', - currentText: 'आज', - monthNames: ['जनवरी ','फरवरी','मार्च','अप्रेल','मई','जून', - 'जूलाई','अगस्त ','सितम्बर','अक्टूबर','नवम्बर','दिसम्बर'], - monthNamesShort: ['जन', 'फर', 'मार्च', 'अप्रेल', 'मई', 'जून', - 'जूलाई', 'अग', 'सित', 'अक्ट', 'नव', 'दि'], - dayNames: ['रविवार', 'सोमवार', 'मंगलवार', 'बुधवार', 'गुरुवार', 'शुक्रवार', 'शनिवार'], - dayNamesShort: ['रवि', 'सोम', 'मंगल', 'बुध', 'गुरु', 'शुक्र', 'शनि'], - dayNamesMin: ['रवि', 'सोम', 'मंगल', 'बुध', 'गुरु', 'शुक्र', 'शनि'], - weekHeader: 'हफ्ता', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['hi']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hr.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hr.js deleted file mode 100644 index 2fe37b64b70..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hr.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Croatian i18n for the jQuery UI date picker plugin. */ -/* Written by Vjekoslav Nesek. */ -jQuery(function($){ - $.datepicker.regional['hr'] = { - closeText: 'Zatvori', - prevText: '<', - nextText: '>', - currentText: 'Danas', - monthNames: ['Siječanj','Veljača','Ožujak','Travanj','Svibanj','Lipanj', - 'Srpanj','Kolovoz','Rujan','Listopad','Studeni','Prosinac'], - monthNamesShort: ['Sij','Velj','Ožu','Tra','Svi','Lip', - 'Srp','Kol','Ruj','Lis','Stu','Pro'], - dayNames: ['Nedjelja','Ponedjeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'], - dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'], - dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], - weekHeader: 'Tje', - dateFormat: 'dd.mm.yy.', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['hr']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hu.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hu.js deleted file mode 100644 index b28c268c1c4..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hu.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Hungarian initialisation for the jQuery UI date picker plugin. */ -/* Written by Istvan Karaszi (jquery@spam.raszi.hu). */ -jQuery(function($){ - $.datepicker.regional['hu'] = { - closeText: 'bezár', - prevText: 'vissza', - nextText: 'előre', - currentText: 'ma', - monthNames: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', - 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'], - monthNamesShort: ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún', - 'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'], - dayNames: ['Vasárnap', 'Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'], - dayNamesShort: ['Vas', 'Hét', 'Ked', 'Sze', 'Csü', 'Pén', 'Szo'], - dayNamesMin: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'], - weekHeader: 'Hét', - dateFormat: 'yy.mm.dd.', - firstDay: 1, - isRTL: false, - showMonthAfterYear: true, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['hu']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hy.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hy.js deleted file mode 100644 index 6d4eca5556b..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-hy.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Armenian(UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* Written by Levon Zakaryan (levon.zakaryan@gmail.com)*/ -jQuery(function($){ - $.datepicker.regional['hy'] = { - closeText: 'Փակել', - prevText: '<Նախ.', - nextText: 'Հաջ.>', - currentText: 'Այսօր', - monthNames: ['Հունվար','Փետրվար','Մարտ','Ապրիլ','Մայիս','Հունիս', - 'Հուլիս','Օգոստոս','Սեպտեմբեր','Հոկտեմբեր','Նոյեմբեր','Դեկտեմբեր'], - monthNamesShort: ['Հունվ','Փետր','Մարտ','Ապր','Մայիս','Հունիս', - 'Հուլ','Օգս','Սեպ','Հոկ','Նոյ','Դեկ'], - dayNames: ['կիրակի','եկուշաբթի','երեքշաբթի','չորեքշաբթի','հինգշաբթի','ուրբաթ','շաբաթ'], - dayNamesShort: ['կիր','երկ','երք','չրք','հնգ','ուրբ','շբթ'], - dayNamesMin: ['կիր','երկ','երք','չրք','հնգ','ուրբ','շբթ'], - weekHeader: 'ՇԲՏ', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['hy']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-id.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-id.js deleted file mode 100644 index 6327fa60c78..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-id.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Indonesian initialisation for the jQuery UI date picker plugin. */ -/* Written by Deden Fathurahman (dedenf@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['id'] = { - closeText: 'Tutup', - prevText: '<mundur', - nextText: 'maju>', - currentText: 'hari ini', - monthNames: ['Januari','Februari','Maret','April','Mei','Juni', - 'Juli','Agustus','September','Oktober','Nopember','Desember'], - monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun', - 'Jul','Agus','Sep','Okt','Nop','Des'], - dayNames: ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'], - dayNamesShort: ['Min','Sen','Sel','Rab','kam','Jum','Sab'], - dayNamesMin: ['Mg','Sn','Sl','Rb','Km','jm','Sb'], - weekHeader: 'Mg', - dateFormat: 'dd/mm/yy', - firstDay: 0, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['id']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-is.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-is.js deleted file mode 100644 index 925341a7a5b..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-is.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Icelandic initialisation for the jQuery UI date picker plugin. */ -/* Written by Haukur H. Thorsson (haukur@eskill.is). */ -jQuery(function($){ - $.datepicker.regional['is'] = { - closeText: 'Loka', - prevText: '< Fyrri', - nextText: 'Næsti >', - currentText: 'Í dag', - monthNames: ['Janúar','Febrúar','Mars','Apríl','Maí','Júní', - 'Júlí','Ágúst','September','Október','Nóvember','Desember'], - monthNamesShort: ['Jan','Feb','Mar','Apr','Maí','Jún', - 'Júl','Ágú','Sep','Okt','Nóv','Des'], - dayNames: ['Sunnudagur','Mánudagur','Þriðjudagur','Miðvikudagur','Fimmtudagur','Föstudagur','Laugardagur'], - dayNamesShort: ['Sun','Mán','Þri','Mið','Fim','Fös','Lau'], - dayNamesMin: ['Su','Má','Þr','Mi','Fi','Fö','La'], - weekHeader: 'Vika', - dateFormat: 'dd/mm/yy', - firstDay: 0, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['is']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-it.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-it.js deleted file mode 100644 index a01f043f8a7..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-it.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Italian initialisation for the jQuery UI date picker plugin. */ -/* Written by Antonello Pasella (antonello.pasella@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['it'] = { - closeText: 'Chiudi', - prevText: '<Prec', - nextText: 'Succ>', - currentText: 'Oggi', - monthNames: ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno', - 'Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'], - monthNamesShort: ['Gen','Feb','Mar','Apr','Mag','Giu', - 'Lug','Ago','Set','Ott','Nov','Dic'], - dayNames: ['Domenica','Lunedì','Martedì','Mercoledì','Giovedì','Venerdì','Sabato'], - dayNamesShort: ['Dom','Lun','Mar','Mer','Gio','Ven','Sab'], - dayNamesMin: ['Do','Lu','Ma','Me','Gi','Ve','Sa'], - weekHeader: 'Sm', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['it']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ja.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ja.js deleted file mode 100644 index 4d0b63c77de..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ja.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Japanese initialisation for the jQuery UI date picker plugin. */ -/* Written by Kentaro SATO (kentaro@ranvis.com). */ -jQuery(function($){ - $.datepicker.regional['ja'] = { - closeText: '閉じる', - prevText: '<前', - nextText: '次>', - currentText: '今日', - monthNames: ['1月','2月','3月','4月','5月','6月', - '7月','8月','9月','10月','11月','12月'], - monthNamesShort: ['1月','2月','3月','4月','5月','6月', - '7月','8月','9月','10月','11月','12月'], - dayNames: ['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'], - dayNamesShort: ['日','月','火','水','木','金','土'], - dayNamesMin: ['日','月','火','水','木','金','土'], - weekHeader: '週', - dateFormat: 'yy/mm/dd', - firstDay: 0, - isRTL: false, - showMonthAfterYear: true, - yearSuffix: '年'}; - $.datepicker.setDefaults($.datepicker.regional['ja']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ka.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ka.js deleted file mode 100644 index c10658d79bf..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ka.js +++ /dev/null @@ -1,21 +0,0 @@ -/* Georgian (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* Written by Lado Lomidze (lado.lomidze@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['ka'] = { - closeText: 'დახურვა', - prevText: '< წინა', - nextText: 'შემდეგი >', - currentText: 'დღეს', - monthNames: ['იანვარი','თებერვალი','მარტი','აპრილი','მაისი','ივნისი', 'ივლისი','აგვისტო','სექტემბერი','ოქტომბერი','ნოემბერი','დეკემბერი'], - monthNamesShort: ['იან','თებ','მარ','აპრ','მაი','ივნ', 'ივლ','აგვ','სექ','ოქტ','ნოე','დეკ'], - dayNames: ['კვირა','ორშაბათი','სამშაბათი','ოთხშაბათი','ხუთშაბათი','პარასკევი','შაბათი'], - dayNamesShort: ['კვ','ორშ','სამ','ოთხ','ხუთ','პარ','შაბ'], - dayNamesMin: ['კვ','ორშ','სამ','ოთხ','ხუთ','პარ','შაბ'], - weekHeader: 'კვირა', - dateFormat: 'dd-mm-yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['ka']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-kk.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-kk.js deleted file mode 100644 index dcd6a65df72..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-kk.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Kazakh (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* Written by Dmitriy Karasyov (dmitriy.karasyov@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['kk'] = { - closeText: 'Жабу', - prevText: '<Алдыңғы', - nextText: 'Келесі>', - currentText: 'Бүгін', - monthNames: ['Қаңтар','Ақпан','Наурыз','Сәуір','Мамыр','Маусым', - 'Шілде','Тамыз','Қыркүйек','Қазан','Қараша','Желтоқсан'], - monthNamesShort: ['Қаң','Ақп','Нау','Сәу','Мам','Мау', - 'Шіл','Там','Қыр','Қаз','Қар','Жел'], - dayNames: ['Жексенбі','Дүйсенбі','Сейсенбі','Сәрсенбі','Бейсенбі','Жұма','Сенбі'], - dayNamesShort: ['жкс','дсн','ссн','срс','бсн','жма','снб'], - dayNamesMin: ['Жк','Дс','Сс','Ср','Бс','Жм','Сн'], - weekHeader: 'Не', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['kk']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-km.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-km.js deleted file mode 100644 index f9c4e3a02d9..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-km.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Khmer initialisation for the jQuery calendar extension. */ -/* Written by Chandara Om (chandara.teacher@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['km'] = { - closeText: 'ធ្វើ​រួច', - prevText: 'មុន', - nextText: 'បន្ទាប់', - currentText: 'ថ្ងៃ​នេះ', - monthNames: ['មករា','កុម្ភៈ','មីនា','មេសា','ឧសភា','មិថុនា', - 'កក្កដា','សីហា','កញ្ញា','តុលា','វិច្ឆិកា','ធ្នូ'], - monthNamesShort: ['មករា','កុម្ភៈ','មីនា','មេសា','ឧសភា','មិថុនា', - 'កក្កដា','សីហា','កញ្ញា','តុលា','វិច្ឆិកា','ធ្នូ'], - dayNames: ['អាទិត្យ', 'ចន្ទ', 'អង្គារ', 'ពុធ', 'ព្រហស្បតិ៍', 'សុក្រ', 'សៅរ៍'], - dayNamesShort: ['អា', 'ច', 'អ', 'ពុ', 'ព្រហ', 'សុ', 'សៅ'], - dayNamesMin: ['អា', 'ច', 'អ', 'ពុ', 'ព្រហ', 'សុ', 'សៅ'], - weekHeader: 'សប្ដាហ៍', - dateFormat: 'dd-mm-yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['km']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ko.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ko.js deleted file mode 100644 index af36f3d6b94..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ko.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Korean initialisation for the jQuery calendar extension. */ -/* Written by DaeKwon Kang (ncrash.dk@gmail.com), Edited by Genie. */ -jQuery(function($){ - $.datepicker.regional['ko'] = { - closeText: '닫기', - prevText: '이전달', - nextText: '다음달', - currentText: '오늘', - monthNames: ['1월','2월','3월','4월','5월','6월', - '7월','8월','9월','10월','11월','12월'], - monthNamesShort: ['1월','2월','3월','4월','5월','6월', - '7월','8월','9월','10월','11월','12월'], - dayNames: ['일요일','월요일','화요일','수요일','목요일','금요일','토요일'], - dayNamesShort: ['일','월','화','수','목','금','토'], - dayNamesMin: ['일','월','화','수','목','금','토'], - weekHeader: 'Wk', - dateFormat: 'yy-mm-dd', - firstDay: 0, - isRTL: false, - showMonthAfterYear: true, - yearSuffix: '년'}; - $.datepicker.setDefaults($.datepicker.regional['ko']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ky.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ky.js deleted file mode 100644 index d4466b12e6e..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ky.js +++ /dev/null @@ -1,24 +0,0 @@ -/* Kyrgyz (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* Written by Sergey Kartashov (ebishkek@yandex.ru). */ -jQuery(function($){ - $.datepicker.regional['ky'] = { - closeText: 'Жабуу', - prevText: '<Мур', - nextText: 'Кий>', - currentText: 'Бүгүн', - monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь', - 'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'], - monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн', - 'Июл','Авг','Сен','Окт','Ноя','Дек'], - dayNames: ['жекшемби', 'дүйшөмбү', 'шейшемби', 'шаршемби', 'бейшемби', 'жума', 'ишемби'], - dayNamesShort: ['жек', 'дүй', 'шей', 'шар', 'бей', 'жум', 'ише'], - dayNamesMin: ['Жк','Дш','Шш','Шр','Бш','Жм','Иш'], - weekHeader: 'Жум', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: '' - }; - $.datepicker.setDefaults($.datepicker.regional['ky']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lb.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lb.js deleted file mode 100644 index 87c79d594eb..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lb.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Luxembourgish initialisation for the jQuery UI date picker plugin. */ -/* Written by Michel Weimerskirch */ -jQuery(function($){ - $.datepicker.regional['lb'] = { - closeText: 'Fäerdeg', - prevText: 'Zréck', - nextText: 'Weider', - currentText: 'Haut', - monthNames: ['Januar','Februar','Mäerz','Abrëll','Mee','Juni', - 'Juli','August','September','Oktober','November','Dezember'], - monthNamesShort: ['Jan', 'Feb', 'Mäe', 'Abr', 'Mee', 'Jun', - 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], - dayNames: ['Sonndeg', 'Méindeg', 'Dënschdeg', 'Mëttwoch', 'Donneschdeg', 'Freideg', 'Samschdeg'], - dayNamesShort: ['Son', 'Méi', 'Dën', 'Mët', 'Don', 'Fre', 'Sam'], - dayNamesMin: ['So','Mé','Dë','Më','Do','Fr','Sa'], - weekHeader: 'W', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['lb']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lt.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lt.js deleted file mode 100644 index 1afaaac5df7..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lt.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Lithuanian (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* @author Arturas Paleicikas */ -jQuery(function($){ - $.datepicker.regional['lt'] = { - closeText: 'Uždaryti', - prevText: '<Atgal', - nextText: 'Pirmyn>', - currentText: 'Šiandien', - monthNames: ['Sausis','Vasaris','Kovas','Balandis','Gegužė','Birželis', - 'Liepa','Rugpjūtis','Rugsėjis','Spalis','Lapkritis','Gruodis'], - monthNamesShort: ['Sau','Vas','Kov','Bal','Geg','Bir', - 'Lie','Rugp','Rugs','Spa','Lap','Gru'], - dayNames: ['sekmadienis','pirmadienis','antradienis','trečiadienis','ketvirtadienis','penktadienis','šeštadienis'], - dayNamesShort: ['sek','pir','ant','tre','ket','pen','šeš'], - dayNamesMin: ['Se','Pr','An','Tr','Ke','Pe','Še'], - weekHeader: 'Wk', - dateFormat: 'yy-mm-dd', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['lt']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lv.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lv.js deleted file mode 100644 index 28cc102fc84..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-lv.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Latvian (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* @author Arturas Paleicikas */ -jQuery(function($){ - $.datepicker.regional['lv'] = { - closeText: 'Aizvērt', - prevText: 'Iepr', - nextText: 'Nāka', - currentText: 'Šodien', - monthNames: ['Janvāris','Februāris','Marts','Aprīlis','Maijs','Jūnijs', - 'Jūlijs','Augusts','Septembris','Oktobris','Novembris','Decembris'], - monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jūn', - 'Jūl','Aug','Sep','Okt','Nov','Dec'], - dayNames: ['svētdiena','pirmdiena','otrdiena','trešdiena','ceturtdiena','piektdiena','sestdiena'], - dayNamesShort: ['svt','prm','otr','tre','ctr','pkt','sst'], - dayNamesMin: ['Sv','Pr','Ot','Tr','Ct','Pk','Ss'], - weekHeader: 'Nav', - dateFormat: 'dd-mm-yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['lv']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-mk.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-mk.js deleted file mode 100644 index 0285325519f..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-mk.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Macedonian i18n for the jQuery UI date picker plugin. */ -/* Written by Stojce Slavkovski. */ -jQuery(function($){ - $.datepicker.regional['mk'] = { - closeText: 'Затвори', - prevText: '<', - nextText: '>', - currentText: 'Денес', - monthNames: ['Јануари','Февруари','Март','Април','Мај','Јуни', - 'Јули','Август','Септември','Октомври','Ноември','Декември'], - monthNamesShort: ['Јан','Фев','Мар','Апр','Мај','Јун', - 'Јул','Авг','Сеп','Окт','Ное','Дек'], - dayNames: ['Недела','Понеделник','Вторник','Среда','Четврток','Петок','Сабота'], - dayNamesShort: ['Нед','Пон','Вто','Сре','Чет','Пет','Саб'], - dayNamesMin: ['Не','По','Вт','Ср','Че','Пе','Са'], - weekHeader: 'Сед', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['mk']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ml.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ml.js deleted file mode 100644 index 9b8f460dbcc..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ml.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Malayalam (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* Written by Saji Nediyanchath (saji89@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['ml'] = { - closeText: 'ശരി', - prevText: 'മുന്നത്തെ', - nextText: 'അടുത്തത് ', - currentText: 'ഇന്ന്', - monthNames: ['ജനുവരി','ഫെബ്രുവരി','മാര്‍ച്ച്','ഏപ്രില്‍','മേയ്','ജൂണ്‍', - 'ജൂലൈ','ആഗസ്റ്റ്','സെപ്റ്റംബര്‍','ഒക്ടോബര്‍','നവംബര്‍','ഡിസംബര്‍'], - monthNamesShort: ['ജനു', 'ഫെബ്', 'മാര്‍', 'ഏപ്രി', 'മേയ്', 'ജൂണ്‍', - 'ജൂലാ', 'ആഗ', 'സെപ്', 'ഒക്ടോ', 'നവം', 'ഡിസ'], - dayNames: ['ഞായര്‍', 'തിങ്കള്‍', 'ചൊവ്വ', 'ബുധന്‍', 'വ്യാഴം', 'വെള്ളി', 'ശനി'], - dayNamesShort: ['ഞായ', 'തിങ്ക', 'ചൊവ്വ', 'ബുധ', 'വ്യാഴം', 'വെള്ളി', 'ശനി'], - dayNamesMin: ['ഞാ','തി','ചൊ','ബു','വ്യാ','വെ','ശ'], - weekHeader: 'ആ', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['ml']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ms.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ms.js deleted file mode 100644 index e70de729959..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ms.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Malaysian initialisation for the jQuery UI date picker plugin. */ -/* Written by Mohd Nawawi Mohamad Jamili (nawawi@ronggeng.net). */ -jQuery(function($){ - $.datepicker.regional['ms'] = { - closeText: 'Tutup', - prevText: '<Sebelum', - nextText: 'Selepas>', - currentText: 'hari ini', - monthNames: ['Januari','Februari','Mac','April','Mei','Jun', - 'Julai','Ogos','September','Oktober','November','Disember'], - monthNamesShort: ['Jan','Feb','Mac','Apr','Mei','Jun', - 'Jul','Ogo','Sep','Okt','Nov','Dis'], - dayNames: ['Ahad','Isnin','Selasa','Rabu','Khamis','Jumaat','Sabtu'], - dayNamesShort: ['Aha','Isn','Sel','Rab','kha','Jum','Sab'], - dayNamesMin: ['Ah','Is','Se','Ra','Kh','Ju','Sa'], - weekHeader: 'Mg', - dateFormat: 'dd/mm/yy', - firstDay: 0, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['ms']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nb.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nb.js deleted file mode 100644 index 845a5052da0..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nb.js +++ /dev/null @@ -1,22 +0,0 @@ -/* Norwegian Bokmål initialisation for the jQuery UI date picker plugin. */ -/* Written by Bjørn Johansen (post@bjornjohansen.no). */ -jQuery(function($){ - $.datepicker.regional['nb'] = { - closeText: 'Lukk', - prevText: '«Forrige', - nextText: 'Neste»', - currentText: 'I dag', - monthNames: ['januar','februar','mars','april','mai','juni','juli','august','september','oktober','november','desember'], - monthNamesShort: ['jan','feb','mar','apr','mai','jun','jul','aug','sep','okt','nov','des'], - dayNamesShort: ['søn','man','tir','ons','tor','fre','lør'], - dayNames: ['søndag','mandag','tirsdag','onsdag','torsdag','fredag','lørdag'], - dayNamesMin: ['sø','ma','ti','on','to','fr','lø'], - weekHeader: 'Uke', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: '' - }; - $.datepicker.setDefaults($.datepicker.regional['nb']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nl-BE.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nl-BE.js deleted file mode 100644 index 7b3cdf425b3..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nl-BE.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Dutch (Belgium) initialisation for the jQuery UI date picker plugin. */ -/* David De Sloovere @DavidDeSloovere */ -jQuery(function($){ - $.datepicker.regional['nl-BE'] = { - closeText: 'Sluiten', - prevText: '←', - nextText: '→', - currentText: 'Vandaag', - monthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', - 'juli', 'augustus', 'september', 'oktober', 'november', 'december'], - monthNamesShort: ['jan', 'feb', 'mrt', 'apr', 'mei', 'jun', - 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'], - dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], - dayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'], - dayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], - weekHeader: 'Wk', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['nl-BE']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nl.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nl.js deleted file mode 100644 index 203f16069d6..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nl.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Dutch (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* Written by Mathias Bynens */ -jQuery(function($){ - $.datepicker.regional.nl = { - closeText: 'Sluiten', - prevText: '←', - nextText: '→', - currentText: 'Vandaag', - monthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', - 'juli', 'augustus', 'september', 'oktober', 'november', 'december'], - monthNamesShort: ['jan', 'feb', 'mrt', 'apr', 'mei', 'jun', - 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'], - dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], - dayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'], - dayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], - weekHeader: 'Wk', - dateFormat: 'dd-mm-yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional.nl); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nn.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nn.js deleted file mode 100644 index b55245ee6b0..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-nn.js +++ /dev/null @@ -1,22 +0,0 @@ -/* Norwegian Nynorsk initialisation for the jQuery UI date picker plugin. */ -/* Written by Bjørn Johansen (post@bjornjohansen.no). */ -jQuery(function($){ - $.datepicker.regional['nn'] = { - closeText: 'Lukk', - prevText: '«Førre', - nextText: 'Neste»', - currentText: 'I dag', - monthNames: ['januar','februar','mars','april','mai','juni','juli','august','september','oktober','november','desember'], - monthNamesShort: ['jan','feb','mar','apr','mai','jun','jul','aug','sep','okt','nov','des'], - dayNamesShort: ['sun','mån','tys','ons','tor','fre','lau'], - dayNames: ['sundag','måndag','tysdag','onsdag','torsdag','fredag','laurdag'], - dayNamesMin: ['su','må','ty','on','to','fr','la'], - weekHeader: 'Veke', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: '' - }; - $.datepicker.setDefaults($.datepicker.regional['nn']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-no.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-no.js deleted file mode 100644 index d36e430be6d..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-no.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Norwegian initialisation for the jQuery UI date picker plugin. */ -/* Written by Naimdjon Takhirov (naimdjon@gmail.com). */ - -jQuery(function($){ - $.datepicker.regional['no'] = { - closeText: 'Lukk', - prevText: '«Forrige', - nextText: 'Neste»', - currentText: 'I dag', - monthNames: ['januar','februar','mars','april','mai','juni','juli','august','september','oktober','november','desember'], - monthNamesShort: ['jan','feb','mar','apr','mai','jun','jul','aug','sep','okt','nov','des'], - dayNamesShort: ['søn','man','tir','ons','tor','fre','lør'], - dayNames: ['søndag','mandag','tirsdag','onsdag','torsdag','fredag','lørdag'], - dayNamesMin: ['sø','ma','ti','on','to','fr','lø'], - weekHeader: 'Uke', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: '' - }; - $.datepicker.setDefaults($.datepicker.regional['no']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pl.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pl.js deleted file mode 100644 index 0ffc515b95b..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pl.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Polish initialisation for the jQuery UI date picker plugin. */ -/* Written by Jacek Wysocki (jacek.wysocki@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['pl'] = { - closeText: 'Zamknij', - prevText: '<Poprzedni', - nextText: 'Następny>', - currentText: 'Dziś', - monthNames: ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec', - 'Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'], - monthNamesShort: ['Sty','Lu','Mar','Kw','Maj','Cze', - 'Lip','Sie','Wrz','Pa','Lis','Gru'], - dayNames: ['Niedziela','Poniedziałek','Wtorek','Środa','Czwartek','Piątek','Sobota'], - dayNamesShort: ['Nie','Pn','Wt','Śr','Czw','Pt','So'], - dayNamesMin: ['N','Pn','Wt','Śr','Cz','Pt','So'], - weekHeader: 'Tydz', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['pl']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pt-BR.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pt-BR.js deleted file mode 100644 index 521967ec39a..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pt-BR.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Brazilian initialisation for the jQuery UI date picker plugin. */ -/* Written by Leonildo Costa Silva (leocsilva@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['pt-BR'] = { - closeText: 'Fechar', - prevText: '<Anterior', - nextText: 'Próximo>', - currentText: 'Hoje', - monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho', - 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], - monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun', - 'Jul','Ago','Set','Out','Nov','Dez'], - dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sábado'], - dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], - dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], - weekHeader: 'Sm', - dateFormat: 'dd/mm/yy', - firstDay: 0, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['pt-BR']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pt.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pt.js deleted file mode 100644 index 999f20e3e96..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-pt.js +++ /dev/null @@ -1,22 +0,0 @@ -/* Portuguese initialisation for the jQuery UI date picker plugin. */ -jQuery(function($){ - $.datepicker.regional['pt'] = { - closeText: 'Fechar', - prevText: '<Anterior', - nextText: 'Seguinte', - currentText: 'Hoje', - monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho', - 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], - monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun', - 'Jul','Ago','Set','Out','Nov','Dez'], - dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sábado'], - dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], - dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], - weekHeader: 'Sem', - dateFormat: 'dd/mm/yy', - firstDay: 0, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['pt']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-rm.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-rm.js deleted file mode 100644 index 22ed21685dd..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-rm.js +++ /dev/null @@ -1,21 +0,0 @@ -/* Romansh initialisation for the jQuery UI date picker plugin. */ -/* Written by Yvonne Gienal (yvonne.gienal@educa.ch). */ -jQuery(function($){ - $.datepicker.regional['rm'] = { - closeText: 'Serrar', - prevText: '<Suandant', - nextText: 'Precedent>', - currentText: 'Actual', - monthNames: ['Schaner','Favrer','Mars','Avrigl','Matg','Zercladur', 'Fanadur','Avust','Settember','October','November','December'], - monthNamesShort: ['Scha','Fev','Mar','Avr','Matg','Zer', 'Fan','Avu','Sett','Oct','Nov','Dec'], - dayNames: ['Dumengia','Glindesdi','Mardi','Mesemna','Gievgia','Venderdi','Sonda'], - dayNamesShort: ['Dum','Gli','Mar','Mes','Gie','Ven','Som'], - dayNamesMin: ['Du','Gl','Ma','Me','Gi','Ve','So'], - weekHeader: 'emna', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['rm']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ro.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ro.js deleted file mode 100644 index a988270d750..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ro.js +++ /dev/null @@ -1,26 +0,0 @@ -/* Romanian initialisation for the jQuery UI date picker plugin. - * - * Written by Edmond L. (ll_edmond@walla.com) - * and Ionut G. Stan (ionut.g.stan@gmail.com) - */ -jQuery(function($){ - $.datepicker.regional['ro'] = { - closeText: 'Închide', - prevText: '« Luna precedentă', - nextText: 'Luna următoare »', - currentText: 'Azi', - monthNames: ['Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie', - 'Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'], - monthNamesShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', - 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - dayNames: ['Duminică', 'Luni', 'Marţi', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă'], - dayNamesShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'], - dayNamesMin: ['Du','Lu','Ma','Mi','Jo','Vi','Sâ'], - weekHeader: 'Săpt', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['ro']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ru.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ru.js deleted file mode 100644 index a519714055d..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ru.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Russian (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* Written by Andrew Stromnov (stromnov@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['ru'] = { - closeText: 'Закрыть', - prevText: '<Пред', - nextText: 'След>', - currentText: 'Сегодня', - monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь', - 'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'], - monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн', - 'Июл','Авг','Сен','Окт','Ноя','Дек'], - dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'], - dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'], - dayNamesMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], - weekHeader: 'Нед', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['ru']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sk.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sk.js deleted file mode 100644 index 0cb76c4e800..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sk.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Slovak initialisation for the jQuery UI date picker plugin. */ -/* Written by Vojtech Rinik (vojto@hmm.sk). */ -jQuery(function($){ - $.datepicker.regional['sk'] = { - closeText: 'Zavrieť', - prevText: '<Predchádzajúci', - nextText: 'Nasledujúci>', - currentText: 'Dnes', - monthNames: ['január','február','marec','apríl','máj','jún', - 'júl','august','september','október','november','december'], - monthNamesShort: ['Jan','Feb','Mar','Apr','Máj','Jún', - 'Júl','Aug','Sep','Okt','Nov','Dec'], - dayNames: ['nedeľa','pondelok','utorok','streda','štvrtok','piatok','sobota'], - dayNamesShort: ['Ned','Pon','Uto','Str','Štv','Pia','Sob'], - dayNamesMin: ['Ne','Po','Ut','St','Št','Pia','So'], - weekHeader: 'Ty', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['sk']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sl.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sl.js deleted file mode 100644 index 048a47af71f..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sl.js +++ /dev/null @@ -1,24 +0,0 @@ -/* Slovenian initialisation for the jQuery UI date picker plugin. */ -/* Written by Jaka Jancar (jaka@kubje.org). */ -/* c = č, s = š z = ž C = Č S = Š Z = Ž */ -jQuery(function($){ - $.datepicker.regional['sl'] = { - closeText: 'Zapri', - prevText: '<Prejšnji', - nextText: 'Naslednji>', - currentText: 'Trenutni', - monthNames: ['Januar','Februar','Marec','April','Maj','Junij', - 'Julij','Avgust','September','Oktober','November','December'], - monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', - 'Jul','Avg','Sep','Okt','Nov','Dec'], - dayNames: ['Nedelja','Ponedeljek','Torek','Sreda','Četrtek','Petek','Sobota'], - dayNamesShort: ['Ned','Pon','Tor','Sre','Čet','Pet','Sob'], - dayNamesMin: ['Ne','Po','To','Sr','Če','Pe','So'], - weekHeader: 'Teden', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['sl']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sq.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sq.js deleted file mode 100644 index d6086a78960..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sq.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Albanian initialisation for the jQuery UI date picker plugin. */ -/* Written by Flakron Bytyqi (flakron@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['sq'] = { - closeText: 'mbylle', - prevText: '<mbrapa', - nextText: 'Përpara>', - currentText: 'sot', - monthNames: ['Janar','Shkurt','Mars','Prill','Maj','Qershor', - 'Korrik','Gusht','Shtator','Tetor','Nëntor','Dhjetor'], - monthNamesShort: ['Jan','Shk','Mar','Pri','Maj','Qer', - 'Kor','Gus','Sht','Tet','Nën','Dhj'], - dayNames: ['E Diel','E Hënë','E Martë','E Mërkurë','E Enjte','E Premte','E Shtune'], - dayNamesShort: ['Di','Hë','Ma','Më','En','Pr','Sh'], - dayNamesMin: ['Di','Hë','Ma','Më','En','Pr','Sh'], - weekHeader: 'Ja', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['sq']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sr-SR.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sr-SR.js deleted file mode 100644 index 810d21daaa4..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sr-SR.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Serbian i18n for the jQuery UI date picker plugin. */ -/* Written by Dejan Dimić. */ -jQuery(function($){ - $.datepicker.regional['sr-SR'] = { - closeText: 'Zatvori', - prevText: '<', - nextText: '>', - currentText: 'Danas', - monthNames: ['Januar','Februar','Mart','April','Maj','Jun', - 'Jul','Avgust','Septembar','Oktobar','Novembar','Decembar'], - monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', - 'Jul','Avg','Sep','Okt','Nov','Dec'], - dayNames: ['Nedelja','Ponedeljak','Utorak','Sreda','Četvrtak','Petak','Subota'], - dayNamesShort: ['Ned','Pon','Uto','Sre','Čet','Pet','Sub'], - dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], - weekHeader: 'Sed', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['sr-SR']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sr.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sr.js deleted file mode 100644 index 1349a26cfd7..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sr.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Serbian i18n for the jQuery UI date picker plugin. */ -/* Written by Dejan Dimić. */ -jQuery(function($){ - $.datepicker.regional['sr'] = { - closeText: 'Затвори', - prevText: '<', - nextText: '>', - currentText: 'Данас', - monthNames: ['Јануар','Фебруар','Март','Април','Мај','Јун', - 'Јул','Август','Септембар','Октобар','Новембар','Децембар'], - monthNamesShort: ['Јан','Феб','Мар','Апр','Мај','Јун', - 'Јул','Авг','Сеп','Окт','Нов','Дец'], - dayNames: ['Недеља','Понедељак','Уторак','Среда','Четвртак','Петак','Субота'], - dayNamesShort: ['Нед','Пон','Уто','Сре','Чет','Пет','Суб'], - dayNamesMin: ['Не','По','Ут','Ср','Че','Пе','Су'], - weekHeader: 'Сед', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['sr']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sv.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sv.js deleted file mode 100644 index cbb5ad135c5..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-sv.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Swedish initialisation for the jQuery UI date picker plugin. */ -/* Written by Anders Ekdahl ( anders@nomadiz.se). */ -jQuery(function($){ - $.datepicker.regional['sv'] = { - closeText: 'Stäng', - prevText: '«Förra', - nextText: 'Nästa»', - currentText: 'Idag', - monthNames: ['Januari','Februari','Mars','April','Maj','Juni', - 'Juli','Augusti','September','Oktober','November','December'], - monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', - 'Jul','Aug','Sep','Okt','Nov','Dec'], - dayNamesShort: ['Sön','Mån','Tis','Ons','Tor','Fre','Lör'], - dayNames: ['Söndag','Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag'], - dayNamesMin: ['Sö','Må','Ti','On','To','Fr','Lö'], - weekHeader: 'Ve', - dateFormat: 'yy-mm-dd', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['sv']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ta.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ta.js deleted file mode 100644 index 40431ed8ec7..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-ta.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Tamil (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* Written by S A Sureshkumar (saskumar@live.com). */ -jQuery(function($){ - $.datepicker.regional['ta'] = { - closeText: 'மூடு', - prevText: 'முன்னையது', - nextText: 'அடுத்தது', - currentText: 'இன்று', - monthNames: ['தை','மாசி','பங்குனி','சித்திரை','வைகாசி','ஆனி', - 'ஆடி','ஆவணி','புரட்டாசி','ஐப்பசி','கார்த்திகை','மார்கழி'], - monthNamesShort: ['தை','மாசி','பங்','சித்','வைகா','ஆனி', - 'ஆடி','ஆவ','புர','ஐப்','கார்','மார்'], - dayNames: ['ஞாயிற்றுக்கிழமை','திங்கட்கிழமை','செவ்வாய்க்கிழமை','புதன்கிழமை','வியாழக்கிழமை','வெள்ளிக்கிழமை','சனிக்கிழமை'], - dayNamesShort: ['ஞாயிறு','திங்கள்','செவ்வாய்','புதன்','வியாழன்','வெள்ளி','சனி'], - dayNamesMin: ['ஞா','தி','செ','பு','வி','வெ','ச'], - weekHeader: 'Не', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['ta']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-th.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-th.js deleted file mode 100644 index aecfd27cc06..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-th.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Thai initialisation for the jQuery UI date picker plugin. */ -/* Written by pipo (pipo@sixhead.com). */ -jQuery(function($){ - $.datepicker.regional['th'] = { - closeText: 'ปิด', - prevText: '« ย้อน', - nextText: 'ถัดไป »', - currentText: 'วันนี้', - monthNames: ['มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน', - 'กรกฎาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'], - monthNamesShort: ['ม.ค.','ก.พ.','มี.ค.','เม.ย.','พ.ค.','มิ.ย.', - 'ก.ค.','ส.ค.','ก.ย.','ต.ค.','พ.ย.','ธ.ค.'], - dayNames: ['อาทิตย์','จันทร์','อังคาร','พุธ','พฤหัสบดี','ศุกร์','เสาร์'], - dayNamesShort: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], - dayNamesMin: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], - weekHeader: 'Wk', - dateFormat: 'dd/mm/yy', - firstDay: 0, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['th']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-tj.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-tj.js deleted file mode 100644 index 9a20e4d3794..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-tj.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Tajiki (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* Written by Abdurahmon Saidov (saidovab@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['tj'] = { - closeText: 'Идома', - prevText: '<Қафо', - nextText: 'Пеш>', - currentText: 'Имрӯз', - monthNames: ['Январ','Феврал','Март','Апрел','Май','Июн', - 'Июл','Август','Сентябр','Октябр','Ноябр','Декабр'], - monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн', - 'Июл','Авг','Сен','Окт','Ноя','Дек'], - dayNames: ['якшанбе','душанбе','сешанбе','чоршанбе','панҷшанбе','ҷумъа','шанбе'], - dayNamesShort: ['якш','душ','сеш','чор','пан','ҷум','шан'], - dayNamesMin: ['Як','Дш','Сш','Чш','Пш','Ҷм','Шн'], - weekHeader: 'Хф', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['tj']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-tr.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-tr.js deleted file mode 100644 index 75b583a778d..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-tr.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Turkish initialisation for the jQuery UI date picker plugin. */ -/* Written by Izzet Emre Erkan (kara@karalamalar.net). */ -jQuery(function($){ - $.datepicker.regional['tr'] = { - closeText: 'kapat', - prevText: '<geri', - nextText: 'ileri>', - currentText: 'bugün', - monthNames: ['Ocak','Şubat','Mart','Nisan','Mayıs','Haziran', - 'Temmuz','Ağustos','Eylül','Ekim','Kasım','Aralık'], - monthNamesShort: ['Oca','Şub','Mar','Nis','May','Haz', - 'Tem','Ağu','Eyl','Eki','Kas','Ara'], - dayNames: ['Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi'], - dayNamesShort: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], - dayNamesMin: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], - weekHeader: 'Hf', - dateFormat: 'dd.mm.yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['tr']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-uk.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-uk.js deleted file mode 100644 index 2bdc82ff701..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-uk.js +++ /dev/null @@ -1,24 +0,0 @@ -/* Ukrainian (UTF-8) initialisation for the jQuery UI date picker plugin. */ -/* Written by Maxim Drogobitskiy (maxdao@gmail.com). */ -/* Corrected by Igor Milla (igor.fsp.milla@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['uk'] = { - closeText: 'Закрити', - prevText: '<', - nextText: '>', - currentText: 'Сьогодні', - monthNames: ['Січень','Лютий','Березень','Квітень','Травень','Червень', - 'Липень','Серпень','Вересень','Жовтень','Листопад','Грудень'], - monthNamesShort: ['Січ','Лют','Бер','Кві','Тра','Чер', - 'Лип','Сер','Вер','Жов','Лис','Гру'], - dayNames: ['неділя','понеділок','вівторок','середа','четвер','п’ятниця','субота'], - dayNamesShort: ['нед','пнд','вів','срд','чтв','птн','сбт'], - dayNamesMin: ['Нд','Пн','Вт','Ср','Чт','Пт','Сб'], - weekHeader: 'Тиж', - dateFormat: 'dd/mm/yy', - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['uk']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-vi.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-vi.js deleted file mode 100644 index b49e7eb130e..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-vi.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Vietnamese initialisation for the jQuery UI date picker plugin. */ -/* Translated by Le Thanh Huy (lthanhhuy@cit.ctu.edu.vn). */ -jQuery(function($){ - $.datepicker.regional['vi'] = { - closeText: 'Đóng', - prevText: '<Trước', - nextText: 'Tiếp>', - currentText: 'Hôm nay', - monthNames: ['Tháng Một', 'Tháng Hai', 'Tháng Ba', 'Tháng Tư', 'Tháng Năm', 'Tháng Sáu', - 'Tháng Bảy', 'Tháng Tám', 'Tháng Chín', 'Tháng Mười', 'Tháng Mười Một', 'Tháng Mười Hai'], - monthNamesShort: ['Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6', - 'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12'], - dayNames: ['Chủ Nhật', 'Thứ Hai', 'Thứ Ba', 'Thứ Tư', 'Thứ Năm', 'Thứ Sáu', 'Thứ Bảy'], - dayNamesShort: ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'], - dayNamesMin: ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'], - weekHeader: 'Tu', - dateFormat: 'dd/mm/yy', - firstDay: 0, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: ''}; - $.datepicker.setDefaults($.datepicker.regional['vi']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-CN.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-CN.js deleted file mode 100644 index d337e4a99ef..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-CN.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Chinese initialisation for the jQuery UI date picker plugin. */ -/* Written by Cloudream (cloudream@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['zh-CN'] = { - closeText: '关闭', - prevText: '<上月', - nextText: '下月>', - currentText: '今天', - monthNames: ['一月','二月','三月','四月','五月','六月', - '七月','八月','九月','十月','十一月','十二月'], - monthNamesShort: ['一月','二月','三月','四月','五月','六月', - '七月','八月','九月','十月','十一月','十二月'], - dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], - dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], - dayNamesMin: ['日','一','二','三','四','五','六'], - weekHeader: '周', - dateFormat: 'yy-mm-dd', - firstDay: 1, - isRTL: false, - showMonthAfterYear: true, - yearSuffix: '年'}; - $.datepicker.setDefaults($.datepicker.regional['zh-CN']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-HK.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-HK.js deleted file mode 100644 index ef6f4e715c2..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-HK.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Chinese initialisation for the jQuery UI date picker plugin. */ -/* Written by SCCY (samuelcychan@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['zh-HK'] = { - closeText: '關閉', - prevText: '<上月', - nextText: '下月>', - currentText: '今天', - monthNames: ['一月','二月','三月','四月','五月','六月', - '七月','八月','九月','十月','十一月','十二月'], - monthNamesShort: ['一月','二月','三月','四月','五月','六月', - '七月','八月','九月','十月','十一月','十二月'], - dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], - dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], - dayNamesMin: ['日','一','二','三','四','五','六'], - weekHeader: '周', - dateFormat: 'dd-mm-yy', - firstDay: 0, - isRTL: false, - showMonthAfterYear: true, - yearSuffix: '年'}; - $.datepicker.setDefaults($.datepicker.regional['zh-HK']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-TW.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-TW.js deleted file mode 100644 index b9105ea507b..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/i18n/jquery.ui.datepicker-zh-TW.js +++ /dev/null @@ -1,23 +0,0 @@ -/* Chinese initialisation for the jQuery UI date picker plugin. */ -/* Written by Ressol (ressol@gmail.com). */ -jQuery(function($){ - $.datepicker.regional['zh-TW'] = { - closeText: '關閉', - prevText: '<上月', - nextText: '下月>', - currentText: '今天', - monthNames: ['一月','二月','三月','四月','五月','六月', - '七月','八月','九月','十月','十一月','十二月'], - monthNamesShort: ['一月','二月','三月','四月','五月','六月', - '七月','八月','九月','十月','十一月','十二月'], - dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], - dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], - dayNamesMin: ['日','一','二','三','四','五','六'], - weekHeader: '周', - dateFormat: 'yy/mm/dd', - firstDay: 1, - isRTL: false, - showMonthAfterYear: true, - yearSuffix: '年'}; - $.datepicker.setDefaults($.datepicker.regional['zh-TW']); -}); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/jquery.timepicker.min.js b/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/jquery.timepicker.min.js deleted file mode 100644 index 61731f64652..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/vendor/jquery.timepicker.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){function b(a){if(a.minTime&&(a.minTime=r(a.minTime)),a.maxTime&&(a.maxTime=r(a.maxTime)),a.durationTime&&"function"!=typeof a.durationTime&&(a.durationTime=r(a.durationTime)),a.disableTimeRanges.length>0){for(var b in a.disableTimeRanges)a.disableTimeRanges[b]=[r(a.disableTimeRanges[b][0]),r(a.disableTimeRanges[b][1])];a.disableTimeRanges=a.disableTimeRanges.sort(function(a,b){return a[0]-b[0]})}return a}function c(b){var c=b.data("timepicker-settings"),d=b.data("timepicker-list");d&&d.length&&(d.remove(),b.data("timepicker-list",!1)),d=a("
        ",{"class":"ui-timepicker-list"});var e=a("
        ",{"class":"ui-timepicker-wrapper",tabindex:-1});e.css({display:"none",position:"absolute"}).append(d),c.className&&e.addClass(c.className),null===c.minTime&&null===c.durationTime||!c.showDuration||e.addClass("ui-timepicker-with-duration");var g=c.minTime;"function"==typeof c.durationTime?g=r(c.durationTime()):null!==c.durationTime&&(g=c.durationTime);var i=null!==c.minTime?c.minTime:0,j=null!==c.maxTime?c.maxTime:i+u-1;i>=j&&(j+=u),j===u-1&&-1!==c.timeFormat.indexOf("H")&&(j=u);for(var k=c.disableTimeRanges,l=0,m=k.length,n=i;j>=n;n+=60*c.step){var s=n,t=a("
      • ");if(t.data("time",s),t.text(q(s,c.timeFormat)),(null!==c.minTime||null!==c.durationTime)&&c.showDuration){var v=a("");v.addClass("ui-timepicker-duration"),v.text(" ("+p(n-g)+")"),t.append(v)}m>l&&(s>=k[l][1]&&(l+=1),k[l]&&s>=k[l][0]&&sb.outerHeight()||0>e)&&b.scrollTop(b.scrollTop()+d.position().top-d.outerHeight()),d.addClass("ui-timepicker-selected")}}}function i(){if(""!==this.value){var b=a(this),c=b.data("timepicker-list");if(!c||!c.is(":visible")){var d=r(this.value);if(null===d)return b.trigger("timeFormatError"),void 0;var e=b.data("timepicker-settings"),f=!1;if(null!==e.minTime&&de.maxTime&&(f=!0),a.each(e.disableTimeRanges,function(){return d>=this[0]&&d=30*e.step?d+=60*e.step-g:d-=g}var h=q(d,e.timeFormat);f?k(b,h,"error")&&b.trigger("timeRangeError"):k(b,h)}}}function j(a){return a.is("input")?a.val():a.data("ui-timepicker-value")}function k(a,b,c){return a.is("input")&&a.val(b),a.data("ui-timepicker-value")!=b?(a.data("ui-timepicker-value",b),"select"==c?a.trigger("selectTime").trigger("changeTime").trigger("change"):"error"!=c&&a.trigger("changeTime"),!0):(a.trigger("selectTime"),!1)}function l(b){var c=a(this),d=c.data("timepicker-list");if(!d||!d.is(":visible")){if(40!=b.keyCode)return m(b,c);f(c)||c.focus()}switch(b.keyCode){case 13:return o(c)&&x.hide.apply(this),b.preventDefault(),!1;case 38:var e=d.find(".ui-timepicker-selected");return e.length?e.is(":first-child")||(e.removeClass("ui-timepicker-selected"),e.prev().addClass("ui-timepicker-selected"),e.prev().position().top0?(e=a(c),!1):void 0}),e.addClass("ui-timepicker-selected")),!1;case 40:return e=d.find(".ui-timepicker-selected"),0===e.length?(d.find("li").each(function(b,c){return a(c).position().top>0?(e=a(c),!1):void 0}),e.addClass("ui-timepicker-selected")):e.is(":last-child")||(e.removeClass("ui-timepicker-selected"),e.next().addClass("ui-timepicker-selected"),e.next().position().top+2*e.outerHeight()>d.outerHeight()&&d.scrollTop(d.scrollTop()+e.outerHeight())),!1;case 27:d.find("li").removeClass("ui-timepicker-selected"),x.hide();break;case 9:x.hide();break;default:return m(b,c)}}function m(a,b){return!b.data("timepicker-settings").disableTextInput||a.ctrlKey||a.altKey||a.metaKey||2!=a.keyCode&&8!=a.keyCode&&a.keyCode<46}function n(b){var c=a(this),d=c.data("timepicker-list");if(!d||!d.is(":visible"))return!0;switch(b.keyCode){case 96:case 97:case 98:case 99:case 100:case 101:case 102:case 103:case 104:case 105:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 65:case 77:case 80:case 186:case 8:case 46:h(c,d);break;default:return}}function o(a){var b=a.data("timepicker-settings"),c=a.data("timepicker-list"),d=null,e=c.find(".ui-timepicker-selected");if(e.hasClass("ui-timepicker-disabled"))return!1;if(e.length?d=e.data("time"):j(a)&&(d=r(j(a)),h(a,c)),null!==d){var f=q(d,b.timeFormat);k(a,f,"select")}return!0}function p(a){var b,c=Math.round(a/60);if(Math.abs(c)<60)b=[c,w.mins];else if(60==c)b=["1",w.hr];else{var d=(c/60).toFixed(1);"."!=w.decimal&&(d=d.replace(".",w.decimal)),b=[d,w.hrs]}return b.join(" ")}function q(a,b){if(null!==a){for(var c,d,e=new Date(t.valueOf()+1e3*a),f="",g=0;g11?"pm":"am";break;case"A":f+=e.getHours()>11?"PM":"AM";break;case"g":c=e.getHours()%12,f+=0===c?"12":c;break;case"G":f+=e.getHours();break;case"h":c=e.getHours()%12,0!==c&&10>c&&(c="0"+c),f+=0===c?"12":c;break;case"H":c=e.getHours(),a===u&&(c=24),f+=c>9?c:"0"+c;break;case"i":var h=e.getMinutes();f+=h>9?h:"0"+h;break;case"s":a=e.getSeconds(),f+=a>9?a:"0"+a;break;default:f+=d}return f}}function r(a){if(""===a)return null;if(!a||a+0==a)return a;"object"==typeof a&&(a=a.getHours()+":"+s(a.getMinutes())+":"+s(a.getSeconds())),a=a.toLowerCase(),new Date(0);var b;if(-1===a.indexOf(":")?(b=a.match(/^([0-9]):?([0-5][0-9])?:?([0-5][0-9])?\s*([pa]?)m?$/),b||(b=a.match(/^([0-2][0-9]):?([0-5][0-9])?:?([0-5][0-9])?\s*([pa]?)m?$/))):b=a.match(/^(\d{1,2})(?::([0-5][0-9]))?(?::([0-5][0-9]))?\s*([pa]?)m?$/),!b)return null;var c,d=parseInt(1*b[1],10);c=b[4]?12==d?"p"==b[4]?12:0:d+("p"==b[4]?12:0):d;var e=1*b[2]||0,f=1*b[3]||0;return 3600*c+60*e+f}function s(a){return("0"+a).slice(-2)}var t=d(),u=86400,v={className:null,minTime:null,maxTime:null,durationTime:null,step:30,showDuration:!1,timeFormat:"g:ia",scrollDefaultNow:!1,scrollDefaultTime:!1,selectOnBlur:!1,disableTouchKeyboard:!0,forceRoundTime:!1,appendTo:"body",disableTimeRanges:[],closeOnWindowScroll:!1,disableTextInput:!1},w={decimal:".",mins:"mins",hr:"hr",hrs:"hrs"},x={init:function(c){return this.each(function(){var d=a(this);if("SELECT"==d[0].tagName){for(var e={type:"text",value:d.val()},f=d[0].attributes,g=0;g",e);d.replaceWith(h),d=h}var j=a.extend({},v);c&&(j=a.extend(j,c)),j.lang&&(w=a.extend(w,j.lang)),j=b(j),d.data("timepicker-settings",j),d.prop("autocomplete","off"),d.on("click.timepicker focus.timepicker",x.show),d.on("change.timepicker",i),d.on("keydown.timepicker",l),d.on("keyup.timepicker",n),d.addClass("ui-timepicker-input"),i.call(d.get(0))})},show:function(){var b=a(this),d=b.data("timepicker-settings");f(b)&&b.blur();var h=b.data("timepicker-list");if(!b.prop("readonly")&&(h&&0!==h.length&&"function"!=typeof d.durationTime||(c(b),h=b.data("timepicker-list")),!h.is(":visible"))){x.hide(),h.show(),b.offset().top+b.outerHeight(!0)+h.outerHeight()>a(window).height()+a(window).scrollTop()?h.offset({left:b.offset().left+parseInt(h.css("marginLeft").replace("px",""),10),top:b.offset().top-h.outerHeight()+parseInt(h.css("marginTop").replace("px",""),10)}):h.offset({left:b.offset().left+parseInt(h.css("marginLeft").replace("px",""),10),top:b.offset().top+b.outerHeight()+parseInt(h.css("marginTop").replace("px",""),10)});var i=h.find(".ui-timepicker-selected");if(i.length||(j(b)?i=g(b,h,r(j(b))):d.scrollDefaultNow?i=g(b,h,r(new Date)):d.scrollDefaultTime!==!1&&(i=g(b,h,r(d.scrollDefaultTime)))),i&&i.length){var k=h.scrollTop()+i.position().top-i.outerHeight();h.scrollTop(k)}else h.scrollTop(0);a("body").on("touchstart.ui-timepicker mousedown.ui-timepicker",e),d.closeOnWindowScroll&&a(window).on("scroll.ui-timepicker",e),b.trigger("showTimepicker")}},hide:function(){a(".ui-timepicker-wrapper:visible").each(function(){var b=a(this),c=b.data("timepicker-input"),d=c.data("timepicker-settings");d&&d.selectOnBlur&&o(c),b.hide(),c.trigger("hideTimepicker")})},option:function(c,d){var e=this,f=e.data("timepicker-settings"),g=e.data("timepicker-list");if("object"==typeof c)f=a.extend(f,c);else if("string"==typeof c&&"undefined"!=typeof d)f[c]=d;else if("string"==typeof c)return f[c];return f=b(f),e.data("timepicker-settings",f),g&&(g.remove(),e.data("timepicker-list",!1)),e},getSecondsFromMidnight:function(){return r(j(this))},getTime:function(a){var b=this;return a||(a=new Date),a.setHours(0,0,0,0),new Date(a.valueOf()+1e3*r(j(b)))},setTime:function(a){var b=this,c=q(r(a),b.data("timepicker-settings").timeFormat);k(b,c),b.data("timepicker-list")&&h(b,b.data("timepicker-list"))},remove:function(){var a=this;a.hasClass("ui-timepicker-input")&&(a.removeAttr("autocomplete","off"),a.removeClass("ui-timepicker-input"),a.removeData("timepicker-settings"),a.off(".timepicker"),a.data("timepicker-list")&&a.data("timepicker-list").remove(),a.removeData("timepicker-list"))}};a.fn.timepicker=function(b){return x[b]?x[b].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof b&&b?(a.error("Method "+b+" does not exist on jQuery.timepicker"),void 0):x.init.apply(this,arguments)}}); \ No newline at end of file diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/vendor/jquery.timepicker.css b/wagtail/wagtailadmin/static/wagtailadmin/scss/vendor/jquery.timepicker.css deleted file mode 100755 index 87c7987c08a..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/vendor/jquery.timepicker.css +++ /dev/null @@ -1,67 +0,0 @@ -.ui-timepicker-wrapper { - overflow-y: auto; - height: 150px; - width: 6.5em; - background: #fff; - border: 1px solid #ddd; - -webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2); - -moz-box-shadow:0 5px 10px rgba(0,0,0,0.2); - box-shadow:0 5px 10px rgba(0,0,0,0.2); - outline: none; - z-index: 10001; - margin: 0; -} - -.ui-timepicker-wrapper.ui-timepicker-with-duration { - width: 11em; -} - -.ui-timepicker-list { - margin: 0; - padding: 0; - list-style: none; -} - -.ui-timepicker-duration { - margin-left: 5px; color: #888; -} - -.ui-timepicker-list:hover .ui-timepicker-duration { - color: #888; -} - -.ui-timepicker-list li { - padding: 3px 0 3px 5px; - cursor: pointer; - white-space: nowrap; - color: #000; - list-style: none; - margin: 0; -} - -.ui-timepicker-list:hover .ui-timepicker-selected { - background: #fff; color: #000; -} - -li.ui-timepicker-selected, -.ui-timepicker-list li:hover, -.ui-timepicker-list .ui-timepicker-selected:hover { - background: #1980EC; color: #fff; -} - -li.ui-timepicker-selected .ui-timepicker-duration, -.ui-timepicker-list li:hover .ui-timepicker-duration { - color: #ccc; -} - -.ui-timepicker-list li.ui-timepicker-disabled, -.ui-timepicker-list li.ui-timepicker-disabled:hover, -.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled { - color: #888; - cursor: default; -} - -.ui-timepicker-list li.ui-timepicker-disabled:hover, -.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled { - background: #f2f2f2; -} diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html b/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html index f6226e0a85a..160853aca44 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html @@ -4,7 +4,6 @@ {% block css %} {% compress css %} - {% endcompress %} @@ -17,7 +16,6 @@ {% compress js %} - diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html index 37d600f07d7..7554cd120e1 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html @@ -27,20 +27,12 @@ {% hook_output 'insert_editor_js' %} {% endcompress %} -{% comment %} - Put it outside compress to be sure that offline compression also works fine. -{% endcomment %} -{% get_localized_datepicker_js %} - {% comment %} Additional js from widgets media. Allows for custom widgets in admin panel. {% endcomment %} {{ edit_handler.form.media.js }} '.format(translation_file) - else: # Don't return anything if language is not supported - return '' - - else: # Don't return anything if we don't use I18N and L10N - return '' - \ No newline at end of file From eea06567085dd3a155f20bf408c046e9a5a3aba1 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 15:37:55 +0100 Subject: [PATCH 045/293] Added seconds to timepicker. Added masks to all datetime pickers --- .../wagtailadmin/static/wagtailadmin/js/page-editor.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js index a8d492ffc52..af624572e6e 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js +++ b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js @@ -56,20 +56,23 @@ function insertRichTextDeleteControl(elem) { function initDateChooser(id) { $('#' + id).datetimepicker({ timepicker: false, - format: 'Y-m-d' + format: 'Y-m-d', + mask: '9999-19-39' }); } function initTimeChooser(id) { $('#' + id).datetimepicker({ datepicker: false, - format: 'H:i' + format: 'H:i:s', + mask: '29:59:59' }); } function initDateTimeChooser(id) { $('#' + id).datetimepicker({ - format: 'Y-m-d H:i' + format: 'Y-m-d H:i:s', + mask: '9999-19-39 29:59:59' }); } From fe71932a49c82028741b3a8d0b4064d06bfafb0b Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 15:56:14 +0100 Subject: [PATCH 046/293] Fixed a couple of references to "localize" templatetags library This was removed in 99a70b3 --- .../wagtailadmin/templates/wagtailadmin/pages/_editor_js.html | 2 +- .../wagtailforms/templates/wagtailforms/index_submissions.html | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html index 7554cd120e1..b8334eae27c 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html @@ -1,4 +1,4 @@ -{% load wagtailadmin_tags compress localize %} +{% load wagtailadmin_tags compress %} {% comment %} Javascript declarations to be included on the 'create page' and 'edit page' views diff --git a/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html b/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html index 00732ee4187..9b5ca941f2c 100644 --- a/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html +++ b/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html @@ -1,6 +1,5 @@ {% extends "wagtailadmin/base.html" %} {% load i18n %} -{% load localize %} {% block titletag %}{% blocktrans with form_title=form_page.title|capfirst %}Submissions of {{ form_title }}{% endblocktrans %}{% endblock %} {% block bodyclass %}menu-snippets{% endblock %} {% block extra_js %} From 8fa0bc07df85f4bcc1cfcc70c29d179a7cef147b Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 2 Jun 2014 13:27:39 +0100 Subject: [PATCH 047/293] Made login view redirect already logged in users to dashboard. Fixes #25 --- .../account/password_reset/complete.html | 2 +- .../templates/wagtailadmin/login.html | 2 +- .../tests/test_account_management.py | 1 - wagtail/wagtailadmin/urls.py | 10 ++------- wagtail/wagtailadmin/views/account.py | 22 ++++++++++++++++++- 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/account/password_reset/complete.html b/wagtail/wagtailadmin/templates/wagtailadmin/account/password_reset/complete.html index c0cf872e25b..3dc8272b07f 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/account/password_reset/complete.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/account/password_reset/complete.html @@ -13,6 +13,6 @@ {% block furniture %}

        {% trans "Password change successful" %}

        -

        {% trans "Login" %}

        +

        {% trans "Login" %}

        {% endblock %} \ No newline at end of file diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/login.html b/wagtail/wagtailadmin/templates/wagtailadmin/login.html index 012dd32f895..22682500f7d 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/login.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/login.html @@ -20,7 +20,7 @@
      • {% endif %} -
        + {% csrf_token %}

        {% trans "Sign in to Wagtail" %}

        diff --git a/wagtail/wagtailadmin/tests/test_account_management.py b/wagtail/wagtailadmin/tests/test_account_management.py index 95d54d7d936..63c70779b23 100644 --- a/wagtail/wagtailadmin/tests/test_account_management.py +++ b/wagtail/wagtailadmin/tests/test_account_management.py @@ -49,7 +49,6 @@ def test_login_view_post(self): self.assertTrue('_auth_user_id' in self.client.session) self.assertEqual(self.client.session['_auth_user_id'], User.objects.get(username='test').id) - @unittest.expectedFailure # See: https://github.com/torchbox/wagtail/issues/25 def test_already_logged_in_redirect(self): """ This tests that a user who is already logged in is automatically diff --git a/wagtail/wagtailadmin/urls.py b/wagtail/wagtailadmin/urls.py index 8fbf2f6e770..806240c5c59 100644 --- a/wagtail/wagtailadmin/urls.py +++ b/wagtail/wagtailadmin/urls.py @@ -5,15 +5,8 @@ from wagtail.wagtailadmin.views import account, chooser, home, pages, tags, userbar from wagtail.wagtailadmin import hooks -urlpatterns = [ - url( - r'^login/$', 'django.contrib.auth.views.login', { - 'template_name': 'wagtailadmin/login.html', - 'authentication_form': LoginForm, - 'extra_context': {'show_password_reset': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True)}, - }, name='wagtailadmin_login' - ), +urlpatterns = [ # Password reset url( r'^password_reset/$', 'django.contrib.auth.views.password_reset', { @@ -81,6 +74,7 @@ url(r'^tag-autocomplete/$', tags.autocomplete, name='wagtailadmin_tag_autocomplete'), + url(r'^login/$', account.login, name='wagtailadmin_login'), url(r'^account/$', account.account, name='wagtailadmin_account'), url(r'^account/change_password/$', account.change_password, name='wagtailadmin_account_change_password'), url(r'^logout/$', account.logout, name='wagtailadmin_logout'), diff --git a/wagtail/wagtailadmin/views/account.py b/wagtail/wagtailadmin/views/account.py index 8479ea6b0e1..c5e461f55cb 100644 --- a/wagtail/wagtailadmin/views/account.py +++ b/wagtail/wagtailadmin/views/account.py @@ -3,8 +3,13 @@ from django.contrib import messages from django.contrib.auth.forms import SetPasswordForm from django.contrib.auth.decorators import permission_required -from django.contrib.auth.views import logout as auth_logout +from django.contrib.auth.views import logout as auth_logout, login as auth_login from django.utils.translation import ugettext as _ +from django.views.decorators.debug import sensitive_post_parameters +from django.views.decorators.cache import never_cache + +from wagtail.wagtailadmin import forms + @permission_required('wagtailadmin.access_admin') def account(request): @@ -37,6 +42,21 @@ def change_password(request): }) +@sensitive_post_parameters() +@never_cache +def login(request): + if request.user.is_authenticated(): + return redirect('wagtailadmin_home') + else: + return auth_login(request, + template_name='wagtailadmin/login.html', + authentication_form=forms.LoginForm, + extra_context={ + 'show_password_reset': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True), + }, + ) + + def logout(request): response = auth_logout(request, next_page = 'wagtailadmin_login') From 2a84d7ef1dbbc1bb7b93c0bc49b214598c2d8f1d Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 11:57:48 +0100 Subject: [PATCH 048/293] A few improvements to the wagtailforms submission tests --- wagtail/tests/fixtures/test.json | 3 +++ wagtail/wagtailforms/tests.py | 28 +++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/wagtail/tests/fixtures/test.json b/wagtail/tests/fixtures/test.json index 11b82d9f169..541450211c0 100644 --- a/wagtail/tests/fixtures/test.json +++ b/wagtail/tests/fixtures/test.json @@ -183,6 +183,9 @@ "pk": 8, "model": "tests.formpage", "fields": { + "to_address": "to@email.com", + "from_address": "from@email.com", + "subject": "The subject" } }, diff --git a/wagtail/wagtailforms/tests.py b/wagtail/wagtailforms/tests.py index 8ec2ee5c38d..459dbbea4a9 100644 --- a/wagtail/wagtailforms/tests.py +++ b/wagtail/wagtailforms/tests.py @@ -1,32 +1,50 @@ from django.test import TestCase +from django.core import mail from wagtail.wagtailcore.models import Page from wagtail.wagtailforms.models import FormSubmission + class TestFormSubmission(TestCase): fixtures = ['test.json'] def test_get_form(self): response = self.client.get('/contact-us/') + + # Check response self.assertContains(response, """""") - self.assertNotContains(response, "Thank you for your feedback") + self.assertTemplateUsed(response, 'tests/form_page.html') + self.assertTemplateNotUsed(response, 'tests/form_page_landing.html') def test_post_invalid_form(self): response = self.client.post('/contact-us/', { 'your-email': 'bob', 'your-message': 'hello world' }) - self.assertNotContains(response, "Thank you for your feedback") + + # Check response self.assertContains(response, "Enter a valid email address.") + self.assertTemplateUsed(response, 'tests/form_page.html') + self.assertTemplateNotUsed(response, 'tests/form_page_landing.html') def test_post_valid_form(self): response = self.client.post('/contact-us/', { 'your-email': 'bob@example.com', 'your-message': 'hello world' }) - self.assertNotContains(response, "Your email") - self.assertContains(response, "Thank you for your feedback") - form_page = Page.objects.get(url_path='/home/contact-us/') + # Check response + self.assertContains(response, "Thank you for your feedback.") + self.assertTemplateNotUsed(response, 'tests/form_page.html') + self.assertTemplateUsed(response, 'tests/form_page_landing.html') + + # Check that an email was sent + self.assertEqual(len(mail.outbox), 1) + self.assertEqual(mail.outbox[0].subject, "The subject") + self.assertTrue("Your message: hello world" in mail.outbox[0].body) + self.assertEqual(mail.outbox[0].to, ['to@email.com']) + self.assertEqual(mail.outbox[0].from_email, 'from@email.com') + # Check that form submission was saved correctly + form_page = Page.objects.get(url_path='/home/contact-us/') self.assertTrue(FormSubmission.objects.filter(page=form_page, form_data__contains='hello world').exists()) From 7cf899bdbc8835a05a7896fd4eaaa2452d0ddbd8 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 17:03:33 +0100 Subject: [PATCH 049/293] Added test for FormBuilder class --- wagtail/wagtailforms/tests.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/wagtail/wagtailforms/tests.py b/wagtail/wagtailforms/tests.py index 459dbbea4a9..ac18c7fa71e 100644 --- a/wagtail/wagtailforms/tests.py +++ b/wagtail/wagtailforms/tests.py @@ -1,8 +1,10 @@ from django.test import TestCase from django.core import mail +from django import forms from wagtail.wagtailcore.models import Page from wagtail.wagtailforms.models import FormSubmission +from wagtail.wagtailforms.forms import FormBuilder class TestFormSubmission(TestCase): @@ -48,6 +50,26 @@ def test_post_valid_form(self): self.assertTrue(FormSubmission.objects.filter(page=form_page, form_data__contains='hello world').exists()) +class TestFormBuilder(TestCase): + fixtures = ['test.json'] + + def setUp(self): + self.form_page = Page.objects.get(url_path='/home/contact-us/').specific + self.fb = FormBuilder(self.form_page.form_fields.all()) + + def test_fields(self): + """ + This tests that all fields were added to the form with the correct types + """ + form_class = self.fb.get_form_class() + + self.assertTrue('your-email' in form_class.base_fields.keys()) + self.assertTrue('your-message' in form_class.base_fields.keys()) + + self.assertIsInstance(form_class.base_fields['your-email'], forms.EmailField) + self.assertIsInstance(form_class.base_fields['your-message'], forms.CharField) + + class TestFormsBackend(TestCase): fixtures = ['test.json'] From 97a981a7660154027df1da4f8a2cc314e701d037 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 17:12:08 +0100 Subject: [PATCH 050/293] Cleaned up FormBuilder class --- wagtail/wagtailforms/forms.py | 53 +++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/wagtail/wagtailforms/forms.py b/wagtail/wagtailforms/forms.py index f17023a773e..aaf16eb7925 100644 --- a/wagtail/wagtailforms/forms.py +++ b/wagtail/wagtailforms/forms.py @@ -8,22 +8,9 @@ def __init__(self, *args, **kwargs): return super(BaseForm, self).__init__(*args, **kwargs) -class FormBuilder(): - formfields = SortedDict() - +class FormBuilder(object): def __init__(self, fields): - for field in fields: - options = self.get_options(field) - f = getattr(self, "create_"+field.field_type+"_field")(field, options) - self.formfields[field.clean_name] = f - - def get_options(self, field): - options = {} - options['label'] = field.label - options['help_text'] = field.help_text - options['required'] = field.required - options['initial'] = field.default_value - return options + self.fields = fields def create_singleline_field(self, field, options): # TODO: This is a default value - it may need to be changed @@ -72,6 +59,42 @@ def create_checkboxes_field(self, field, options): def create_checkbox_field(self, field, options): return django.forms.BooleanField(**options) + FIELD_TYPES = { + 'singleline': create_singleline_field, + 'multiline': create_multiline_field, + 'date': create_date_field, + 'datetime': create_datetime_field, + 'email': create_email_field, + 'url': create_url_field, + 'number': create_number_field, + 'dropdown': create_dropdown_field, + 'radio': create_radio_field, + 'checkboxes': create_checkboxes_field, + 'checkbox': create_checkbox_field, + } + + @property + def formfields(self): + formfields = SortedDict() + + for field in self.fields: + options = self.get_field_options(field) + + if field.field_type in self.FIELD_TYPES: + formfields[field.clean_name] = self.FIELD_TYPES[field.field_type](self, field, options) + else: + raise Exception("Unrecognised field type: " + form.field_type) + + return formfields + + def get_field_options(self, field): + options = {} + options['label'] = field.label + options['help_text'] = field.help_text + options['required'] = field.required + options['initial'] = field.default_value + return options + def get_form_class(self): return type('WagtailForm', (BaseForm,), self.formfields) From 21ac2e3ab8bb3c52b45b7ae005a5c87a83785def Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 17:27:48 +0100 Subject: [PATCH 051/293] Split wagtailforms landing page into separate view --- wagtail/wagtailforms/models.py | 26 +++++++++++++++++--------- wagtail/wagtailforms/tests.py | 12 +++++++++--- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/wagtail/wagtailforms/models.py b/wagtail/wagtailforms/models.py index 75f0eceee07..59941c6abd3 100644 --- a/wagtail/wagtailforms/models.py +++ b/wagtail/wagtailforms/models.py @@ -1,5 +1,5 @@ from django.db import models -from django.shortcuts import render +from django.shortcuts import render, redirect from django.utils.translation import ugettext_lazy as _ from django.utils.text import slugify @@ -111,6 +111,7 @@ class AbstractForm(Page): """A Form Page. Pages implementing a form should inhert from it""" form_builder = FormBuilder + landing_page_path = 'done' is_abstract = True # Don't display me in "Add" def __init__(self, *args, **kwargs): @@ -152,11 +153,8 @@ def serve(self, request): form_processor = self.form_processing_backend() form_processor.process(self, form) - # render the landing_page - # TODO: It is much better to redirect to it - return render(request, self.landing_page_template, { - 'self': self, - }) + # Redirect to the landing page + return redirect(self.url + self.landing_page_path + '/') else: form = form_class(**form_params) @@ -165,6 +163,18 @@ def serve(self, request): 'form': form, }) + def serve_landing(self, request): + return render(request, self.landing_page_template, { + 'self': self, + }) + + def route(self, request, path_components): + # Check if this request is for the landing page + if self.live and path_components == [self.landing_page_path]: + return self.serve_landing(request) + + return super(AbstractForm, self).route(request, path_components) + def get_page_modes(self): return [ ('form', 'Form'), @@ -173,9 +183,7 @@ def get_page_modes(self): def show_as_mode(self, mode): if mode == 'landing': - return render(self.dummy_request(), self.landing_page_template, { - 'self': self, - }) + return self.serve_landing(self.dummy_request()) else: return super(AbstractForm, self).show_as_mode(mode) diff --git a/wagtail/wagtailforms/tests.py b/wagtail/wagtailforms/tests.py index ac18c7fa71e..2276d10d97e 100644 --- a/wagtail/wagtailforms/tests.py +++ b/wagtail/wagtailforms/tests.py @@ -34,9 +34,7 @@ def test_post_valid_form(self): }) # Check response - self.assertContains(response, "Thank you for your feedback.") - self.assertTemplateNotUsed(response, 'tests/form_page.html') - self.assertTemplateUsed(response, 'tests/form_page_landing.html') + self.assertEqual(response.status_code, 302) # Check that an email was sent self.assertEqual(len(mail.outbox), 1) @@ -49,6 +47,14 @@ def test_post_valid_form(self): form_page = Page.objects.get(url_path='/home/contact-us/') self.assertTrue(FormSubmission.objects.filter(page=form_page, form_data__contains='hello world').exists()) + def test_get_landing_page(self): + response = self.client.get('/contact-us/done/') + + # Check response + self.assertContains(response, "Thank you for your feedback.") + self.assertTemplateNotUsed(response, 'tests/form_page.html') + self.assertTemplateUsed(response, 'tests/form_page_landing.html') + class TestFormBuilder(TestCase): fixtures = ['test.json'] From 6d67749f5a084b22a8ac9eac5894bfdf2e9dbd66 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 4 Jun 2014 15:48:48 +0100 Subject: [PATCH 052/293] Cleanup of TestFormsBackend TestcAse --- wagtail/wagtailforms/tests.py | 38 +++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/wagtail/wagtailforms/tests.py b/wagtail/wagtailforms/tests.py index 2276d10d97e..019f992d86a 100644 --- a/wagtail/wagtailforms/tests.py +++ b/wagtail/wagtailforms/tests.py @@ -79,31 +79,43 @@ def test_fields(self): class TestFormsBackend(TestCase): fixtures = ['test.json'] - def test_cannot_see_forms_without_permission(self): - form_page = Page.objects.get(url_path='/home/contact-us/') + def setUp(self): + self.client.login(username='siteeditor', password='password') + self.form_page = Page.objects.get(url_path='/home/contact-us/') + def test_cannot_see_forms_without_permission(self): + # Login with as a user without permission to see forms self.client.login(username='eventeditor', password='password') + response = self.client.get('/admin/forms/') - self.assertFalse(form_page in response.context['form_pages']) - def test_can_see_forms_with_permission(self): - form_page = Page.objects.get(url_path='/home/contact-us/') + # Check that the user cannot see the form page + self.assertFalse(self.form_page in response.context['form_pages']) - self.client.login(username='siteeditor', password='password') + def test_can_see_forms_with_permission(self): response = self.client.get('/admin/forms/') - self.assertTrue(form_page in response.context['form_pages']) - def test_can_get_submissions(self): - form_page = Page.objects.get(url_path='/home/contact-us/') + # Check that the user can see the form page + self.assertTrue(self.form_page in response.context['form_pages']) - self.client.login(username='siteeditor', password='password') + def test_list_submissions(self): + response = self.client.get('/admin/forms/submissions/%d/' % self.form_page.id) - response = self.client.get('/admin/forms/submissions/%d/' % form_page.id) + # Check response + self.assertEqual(response.status_code, 200) self.assertEqual(len(response.context['data_rows']), 2) - response = self.client.get('/admin/forms/submissions/%d/?date_from=01%%2F01%%2F2014' % form_page.id) + def test_list_submissions_filtered(self): + response = self.client.get('/admin/forms/submissions/%d/?date_from=01%%2F01%%2F2014' % self.form_page.id) + + # Check response + self.assertEqual(response.status_code, 200) self.assertEqual(len(response.context['data_rows']), 1) - response = self.client.get('/admin/forms/submissions/%d/?date_from=01%%2F01%%2F2014&action=CSV' % form_page.id) + def test_list_submissions_csv_export(self): + response = self.client.get('/admin/forms/submissions/%d/?date_from=01%%2F01%%2F2014&action=CSV' % self.form_page.id) + + # Check response + self.assertEqual(response.status_code, 200) data_line = response.content.split("\n")[1] self.assertTrue('new@example.com' in data_line) From 7e7885b2b514856de0b53c513f2450201be573a6 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 4 Jun 2014 15:55:25 +0100 Subject: [PATCH 053/293] Added tests for wagtailforms page modes --- wagtail/wagtailforms/tests.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/wagtail/wagtailforms/tests.py b/wagtail/wagtailforms/tests.py index 019f992d86a..ab65f909b6d 100644 --- a/wagtail/wagtailforms/tests.py +++ b/wagtail/wagtailforms/tests.py @@ -56,6 +56,29 @@ def test_get_landing_page(self): self.assertTemplateUsed(response, 'tests/form_page_landing.html') +class TestPageModes(TestCase): + fixtures = ['test.json'] + + def setUp(self): + self.form_page = Page.objects.get(url_path='/home/contact-us/').specific + + def test_form(self): + response = self.form_page.show_as_mode('form') + + # Check response + self.assertContains(response, """""") + self.assertTemplateUsed(response, 'tests/form_page.html') + self.assertTemplateNotUsed(response, 'tests/form_page_landing.html') + + def test_landing(self): + response = self.form_page.show_as_mode('landing') + + # Check response + self.assertContains(response, "Thank you for your feedback.") + self.assertTemplateNotUsed(response, 'tests/form_page.html') + self.assertTemplateUsed(response, 'tests/form_page_landing.html') + + class TestFormBuilder(TestCase): fixtures = ['test.json'] From 24df26c8c338562e64dad8440709175d99f488fe Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 4 Jun 2014 16:25:05 +0100 Subject: [PATCH 054/293] More wagtailforms tests --- wagtail/wagtailforms/tests.py | 127 +++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 2 deletions(-) diff --git a/wagtail/wagtailforms/tests.py b/wagtail/wagtailforms/tests.py index ab65f909b6d..5145eae3f86 100644 --- a/wagtail/wagtailforms/tests.py +++ b/wagtail/wagtailforms/tests.py @@ -1,3 +1,5 @@ +import json + from django.test import TestCase from django.core import mail from django import forms @@ -5,6 +7,7 @@ from wagtail.wagtailcore.models import Page from wagtail.wagtailforms.models import FormSubmission from wagtail.wagtailforms.forms import FormBuilder +from wagtail.tests.models import FormPage class TestFormSubmission(TestCase): @@ -99,13 +102,74 @@ def test_fields(self): self.assertIsInstance(form_class.base_fields['your-message'], forms.CharField) -class TestFormsBackend(TestCase): +class TestFormsIndex(TestCase): fixtures = ['test.json'] def setUp(self): self.client.login(username='siteeditor', password='password') self.form_page = Page.objects.get(url_path='/home/contact-us/') + def make_form_pages(self): + """ + This makes 100 form pages and adds them as children to 'contact-us' + This is used to test pagination on the forms index + """ + for i in range(100): + self.form_page.add_child(instance=FormPage( + title="Form " + str(i), + slug='form-' + str(i), + live=True + )) + + def test_forms_index(self): + response = self.client.get('/admin/forms/') + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index.html') + + def test_forms_index_pagination(self): + # Create some more form pages to make pagination kick in + self.make_form_pages() + + # Get page two + response = self.client.get('/admin/forms/', {'p': 2}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index.html') + + # Check that we got the correct page + self.assertEqual(response.context['form_pages'].number, 2) + + def test_forms_index_pagination_invalid(self): + # Create some more form pages to make pagination kick in + self.make_form_pages() + + # Get page two + response = self.client.get('/admin/forms/', {'p': 'Hello world!'}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index.html') + + # Check that it got page one + self.assertEqual(response.context['form_pages'].number, 1) + + def test_forms_index_pagination_out_of_range(self): + # Create some more form pages to make pagination kick in + self.make_form_pages() + + # Get page two + response = self.client.get('/admin/forms/', {'p': 99999}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index.html') + + # Check that it got the last page + self.assertEqual(response.context['form_pages'].number, response.context['form_pages'].paginator.num_pages) + def test_cannot_see_forms_without_permission(self): # Login with as a user without permission to see forms self.client.login(username='eventeditor', password='password') @@ -121,20 +185,79 @@ def test_can_see_forms_with_permission(self): # Check that the user can see the form page self.assertTrue(self.form_page in response.context['form_pages']) + +class TestFormsSubmissions(TestCase): + fixtures = ['test.json'] + + def setUp(self): + self.client.login(username='siteeditor', password='password') + self.form_page = Page.objects.get(url_path='/home/contact-us/') + + def make_list_submissions(self): + """ + This makes 100 submissions to test pagination on the forms submissions page + """ + for i in range(100): + submission = FormSubmission( + page=self.form_page, + form_data=json.dumps({ + 'hello': 'world' + }) + ) + submission.save() + def test_list_submissions(self): response = self.client.get('/admin/forms/submissions/%d/' % self.form_page.id) # Check response self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') self.assertEqual(len(response.context['data_rows']), 2) - def test_list_submissions_filtered(self): + def test_list_submissions_filtering(self): response = self.client.get('/admin/forms/submissions/%d/?date_from=01%%2F01%%2F2014' % self.form_page.id) # Check response self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') self.assertEqual(len(response.context['data_rows']), 1) + def test_list_submissions_pagination(self): + self.make_list_submissions() + + response = self.client.get('/admin/forms/submissions/%d/' % self.form_page.id, {'p': 2}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') + + # Check that we got the correct page + self.assertEqual(response.context['submissions'].number, 2) + + def test_list_submissions_pagination_invalid(self): + self.make_list_submissions() + + response = self.client.get('/admin/forms/submissions/%d/' % self.form_page.id, {'p': 'Hello World!'}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') + + # Check that we got page one + self.assertEqual(response.context['submissions'].number, 1) + + def test_list_submissions_pagination_out_of_range(self): + self.make_list_submissions() + + response = self.client.get('/admin/forms/submissions/%d/' % self.form_page.id, {'p': 99999}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailforms/index_submissions.html') + + # Check that we got the last page + self.assertEqual(response.context['submissions'].number, response.context['submissions'].paginator.num_pages) + def test_list_submissions_csv_export(self): response = self.client.get('/admin/forms/submissions/%d/?date_from=01%%2F01%%2F2014&action=CSV' % self.form_page.id) From 2b4b19a6414d2a20654baf540fb89df907622de0 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 4 Jun 2014 16:38:44 +0100 Subject: [PATCH 055/293] Use reversed URLs in wagtailforms tests --- wagtail/wagtailforms/tests.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/wagtail/wagtailforms/tests.py b/wagtail/wagtailforms/tests.py index 5145eae3f86..24bace8c521 100644 --- a/wagtail/wagtailforms/tests.py +++ b/wagtail/wagtailforms/tests.py @@ -3,6 +3,7 @@ from django.test import TestCase from django.core import mail from django import forms +from django.core.urlresolvers import reverse from wagtail.wagtailcore.models import Page from wagtail.wagtailforms.models import FormSubmission @@ -122,7 +123,7 @@ def make_form_pages(self): )) def test_forms_index(self): - response = self.client.get('/admin/forms/') + response = self.client.get(reverse('wagtailforms_index')) # Check response self.assertEqual(response.status_code, 200) @@ -133,7 +134,7 @@ def test_forms_index_pagination(self): self.make_form_pages() # Get page two - response = self.client.get('/admin/forms/', {'p': 2}) + response = self.client.get(reverse('wagtailforms_index'), {'p': 2}) # Check response self.assertEqual(response.status_code, 200) @@ -147,7 +148,7 @@ def test_forms_index_pagination_invalid(self): self.make_form_pages() # Get page two - response = self.client.get('/admin/forms/', {'p': 'Hello world!'}) + response = self.client.get(reverse('wagtailforms_index'), {'p': 'Hello world!'}) # Check response self.assertEqual(response.status_code, 200) @@ -161,7 +162,7 @@ def test_forms_index_pagination_out_of_range(self): self.make_form_pages() # Get page two - response = self.client.get('/admin/forms/', {'p': 99999}) + response = self.client.get(reverse('wagtailforms_index'), {'p': 99999}) # Check response self.assertEqual(response.status_code, 200) @@ -174,13 +175,13 @@ def test_cannot_see_forms_without_permission(self): # Login with as a user without permission to see forms self.client.login(username='eventeditor', password='password') - response = self.client.get('/admin/forms/') + response = self.client.get(reverse('wagtailforms_index')) # Check that the user cannot see the form page self.assertFalse(self.form_page in response.context['form_pages']) def test_can_see_forms_with_permission(self): - response = self.client.get('/admin/forms/') + response = self.client.get(reverse('wagtailforms_index')) # Check that the user can see the form page self.assertTrue(self.form_page in response.context['form_pages']) @@ -207,7 +208,7 @@ def make_list_submissions(self): submission.save() def test_list_submissions(self): - response = self.client.get('/admin/forms/submissions/%d/' % self.form_page.id) + response = self.client.get(reverse('wagtailforms_list_submissions', args=(self.form_page.id, ))) # Check response self.assertEqual(response.status_code, 200) @@ -215,7 +216,7 @@ def test_list_submissions(self): self.assertEqual(len(response.context['data_rows']), 2) def test_list_submissions_filtering(self): - response = self.client.get('/admin/forms/submissions/%d/?date_from=01%%2F01%%2F2014' % self.form_page.id) + response = self.client.get(reverse('wagtailforms_list_submissions', args=(self.form_page.id, )), {'date_from': '01/01/2014'}) # Check response self.assertEqual(response.status_code, 200) @@ -225,7 +226,7 @@ def test_list_submissions_filtering(self): def test_list_submissions_pagination(self): self.make_list_submissions() - response = self.client.get('/admin/forms/submissions/%d/' % self.form_page.id, {'p': 2}) + response = self.client.get(reverse('wagtailforms_list_submissions', args=(self.form_page.id, )), {'p': 2}) # Check response self.assertEqual(response.status_code, 200) @@ -237,7 +238,7 @@ def test_list_submissions_pagination(self): def test_list_submissions_pagination_invalid(self): self.make_list_submissions() - response = self.client.get('/admin/forms/submissions/%d/' % self.form_page.id, {'p': 'Hello World!'}) + response = self.client.get(reverse('wagtailforms_list_submissions', args=(self.form_page.id, )), {'p': 'Hello World!'}) # Check response self.assertEqual(response.status_code, 200) @@ -249,7 +250,7 @@ def test_list_submissions_pagination_invalid(self): def test_list_submissions_pagination_out_of_range(self): self.make_list_submissions() - response = self.client.get('/admin/forms/submissions/%d/' % self.form_page.id, {'p': 99999}) + response = self.client.get(reverse('wagtailforms_list_submissions', args=(self.form_page.id, )), {'p': 99999}) # Check response self.assertEqual(response.status_code, 200) @@ -259,7 +260,7 @@ def test_list_submissions_pagination_out_of_range(self): self.assertEqual(response.context['submissions'].number, response.context['submissions'].paginator.num_pages) def test_list_submissions_csv_export(self): - response = self.client.get('/admin/forms/submissions/%d/?date_from=01%%2F01%%2F2014&action=CSV' % self.form_page.id) + response = self.client.get(reverse('wagtailforms_list_submissions', args=(self.form_page.id, )), {'date_from': '01/01/2014', 'action': 'CSV'}) # Check response self.assertEqual(response.status_code, 200) From 2f029fc336510ab40fc9cb29c3eaf74e3f252134 Mon Sep 17 00:00:00 2001 From: Ben Margolis Date: Wed, 4 Jun 2014 11:28:14 -0700 Subject: [PATCH 056/293] adding custom img attrs to image_tags, but no custom TestCasecreated for it --- wagtail/wagtailimages/models.py | 5 ++- .../templates/wagtailimages/imagetag.html | 1 + .../wagtailimages/templatetags/image_tags.py | 41 +++++++++++++------ 3 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 wagtail/wagtailimages/templates/wagtailimages/imagetag.html diff --git a/wagtail/wagtailimages/models.py b/wagtail/wagtailimages/models.py index 24fd1f0bf18..bd2fc875178 100644 --- a/wagtail/wagtailimages/models.py +++ b/wagtail/wagtailimages/models.py @@ -12,6 +12,7 @@ from django.utils.html import escape from django.conf import settings from django.utils.translation import ugettext_lazy as _ +from django.template.loader import render_to_string from unidecode import unidecode @@ -225,9 +226,9 @@ class AbstractRendition(models.Model): def url(self): return self.file.url - def img_tag(self): + def img_tag(self, attrs={}): return mark_safe( - '%s' % (escape(self.url), self.width, self.height, escape(self.image.title)) + render_to_string('wagtailimages/imagetag.html',{'self' : self, 'attrs' : attrs, }) ) class Meta: diff --git a/wagtail/wagtailimages/templates/wagtailimages/imagetag.html b/wagtail/wagtailimages/templates/wagtailimages/imagetag.html new file mode 100644 index 00000000000..d1049673927 --- /dev/null +++ b/wagtail/wagtailimages/templates/wagtailimages/imagetag.html @@ -0,0 +1 @@ +{{ self.image.title }} \ No newline at end of file diff --git a/wagtail/wagtailimages/templatetags/image_tags.py b/wagtail/wagtailimages/templatetags/image_tags.py index e59d9cd1486..48800d92078 100644 --- a/wagtail/wagtailimages/templatetags/image_tags.py +++ b/wagtail/wagtailimages/templatetags/image_tags.py @@ -7,32 +7,46 @@ # Local cache of filters, avoid hitting the DB filters = {} + @register.tag(name="image") def image(parser, token): - args = token.split_contents() + bits = token.split_contents()[1:] + image_var = bits[0] + filter_spec = bits[1] + bits = bits[2:] - if len(args) == 3: + if len(bits) == 0: # token is of the form {% image self.photo max-320x200 %} - tag_name, image_var, filter_spec = args return ImageNode(image_var, filter_spec) - elif len(args) == 5: + elif len(bits) == 2: # token is of the form {% image self.photo max-320x200 as img %} - tag_name, image_var, filter_spec, as_token, out_var = args - if as_token != 'as': - raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 %%} or {%% image self.photo max-320x200 as img %%}") + if bits[0] == 'as': + return ImageNode(image_var, filter_spec, output_var_name=bits[1]) + + if len(bits) > 0: + # customized attrs + attrs = {} + for bit in bits: + try: + name,value = bit.split('=') + except: + raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 [ custom-attr=\"value\" [ ... ] ] %%} or {%% image self.photo max-320x200 as img %%}") + if name + attrs[name] = parser.compile_filter(value) # setup to resolve context variables as value - return ImageNode(image_var, filter_spec, out_var) + return ImageNode(image_var, filter_spec, attrs=attrs) - else: - raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 %%} or {%% image self.photo max-320x200 as img %%}") + # something is wrong if we made it this far + raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 [ custom-attr=\"value\" [ ... ] ] %%} or {%% image self.photo max-320x200 as img %%}") class ImageNode(template.Node): - def __init__(self, image_var_name, filter_spec, output_var_name=None): + def __init__(self, image_var_name, filter_spec, output_var_name=None, attrs={}): self.image_var = template.Variable(image_var_name) self.output_var_name = output_var_name + self.attrs = attrs if filter_spec not in filters: filters[filter_spec], _ = Filter.objects.get_or_create(spec=filter_spec) @@ -66,4 +80,7 @@ def render(self, context): return '' else: # render the rendition's image tag now - return rendition.img_tag() + resolved_attrs = {} + for key in self.attrs: + resolved_attrs[key] = self.attrs[key].resolve(context) + return rendition.img_tag(resolved_attrs) From f70768cc4e65dd07bf51629a07387f9dd6c959e0 Mon Sep 17 00:00:00 2001 From: Ben Margolis Date: Wed, 4 Jun 2014 12:52:17 -0700 Subject: [PATCH 057/293] typo --- wagtail/wagtailimages/templatetags/image_tags.py | 1 - 1 file changed, 1 deletion(-) diff --git a/wagtail/wagtailimages/templatetags/image_tags.py b/wagtail/wagtailimages/templatetags/image_tags.py index 48800d92078..e8a4c2191ba 100644 --- a/wagtail/wagtailimages/templatetags/image_tags.py +++ b/wagtail/wagtailimages/templatetags/image_tags.py @@ -33,7 +33,6 @@ def image(parser, token): name,value = bit.split('=') except: raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 [ custom-attr=\"value\" [ ... ] ] %%} or {%% image self.photo max-320x200 as img %%}") - if name attrs[name] = parser.compile_filter(value) # setup to resolve context variables as value return ImageNode(image_var, filter_spec, attrs=attrs) From 0adab4f58d69c86b5ff6aab17efc7ede8c3f3823 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 5 Jun 2014 15:42:26 +0100 Subject: [PATCH 058/293] updates to tabs and forms --- .../wagtailadmin/static/wagtailadmin/scss/components/forms.scss | 1 + .../wagtailadmin/static/wagtailadmin/scss/components/tabs.scss | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss index 29c44b4f3b8..3a6fc0d21ce 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss @@ -68,6 +68,7 @@ input, textarea, select, .richtext, .tagit{ } /* select boxes */ +.choice_field .input, .typed_choice_field .input{ position:relative; diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss index 7cd9a939743..984766b04f3 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss @@ -40,7 +40,7 @@ &:after{ @include border-radius(50px); - @include box-shadow(1px 1px 2px rgba(0, 0, 0, 0.2)); + @include box-shadow(1px 2px 2px rgba(0, 0, 0, 0.1)); position:absolute; right:-0.5em; top:-0.5em; From b177c9fab40f1083ddb97227f6bbe16dc0596497 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 5 Jun 2014 17:05:21 +0100 Subject: [PATCH 059/293] styled datepicker nicer --- .../static/wagtailadmin/js/page-editor.js | 7 +- .../scss/components/datetimepicker.scss | 304 ++++++++++++++++++ .../static/wagtailadmin/scss/core.scss | 1 + .../scss/vendor/jquery.datetimepicker.css | 304 ------------------ .../templates/wagtailadmin/admin_base.html | 1 - 5 files changed, 307 insertions(+), 310 deletions(-) create mode 100644 wagtail/wagtailadmin/static/wagtailadmin/scss/components/datetimepicker.scss delete mode 100644 wagtail/wagtailadmin/static/wagtailadmin/scss/vendor/jquery.datetimepicker.css diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js index 7f27c4a3705..0d6c4d51f1b 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js +++ b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js @@ -57,22 +57,19 @@ function initDateChooser(id) { $('#' + id).datetimepicker({ timepicker: false, format: 'Y-m-d', - mask: '9999-19-39' }); } function initTimeChooser(id) { $('#' + id).datetimepicker({ datepicker: false, - format: 'H:i:s', - mask: '29:59:59' + format: 'H:i', }); } function initDateTimeChooser(id) { $('#' + id).datetimepicker({ - format: 'Y-m-d H:i:s', - mask: '9999-19-39 29:59:59' + format: 'Y-m-d H:i', }); } diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/datetimepicker.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/datetimepicker.scss new file mode 100644 index 00000000000..078c9346999 --- /dev/null +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/datetimepicker.scss @@ -0,0 +1,304 @@ +.xdsoft_datetimepicker{ + box-shadow: 0px 5px 10px -5px rgba(0, 0, 0, 0.4); + background: #FFFFFF; + border:1px solid darken($color-input-focus, 40%); + display: block; + padding: 8px; + padding-left: 0px; + padding-top: 2px; + position: absolute; + z-index: 9999; + -moz-box-sizing: border-box; + box-sizing: border-box; + display:none; + + *{ + -moz-box-sizing: border-box; + box-sizing: border-box; + padding:0px; + margin:0px; + } + + iframe { + position: absolute; + left: 0; + top: 0; + width: 75px; + height: 210px; + background: transparent; + border:none; + } + + .xdsoft_datepicker, .xdsoft_timepicker{ + display:none; + + &.active{ + display:block; + } + } + .xdsoft_datepicker{ + float:left; + margin-left:8px; + } + .xdsoft_datepicker.active + .xdsoft_timepicker{ + margin-top:8px; + margin-bottom:3px + } + .xdsoft_mounthpicker{ + position: relative; + text-align: center; + } + + .xdsoft_next, .xdsoft_prev, .xdsoft_today_button{ + background-color: transparent; + cursor: pointer; + display: block; + border:0; + overflow: hidden; + padding: 5px 0px; + position: relative; + white-space: nowrap; + width: 2em; + color:$color-teal; + text-transform:none; + text-align:center; + + &:before{ + font-size:1.5em; + font-family:wagtail; + width:1em; + line-height:1.3em; + text-align:center; + margin:0; + } + &:hover{ + color:$color-teal-darker; + } + } + .xdsoft_prev{ + float: left; + + &:before{ + content:"z"; + } + } + .xdsoft_today_button{ + float: left; + margin-left:5px; + + &:before{ + content:"W"; + } + } + + .xdsoft_next{ + float: right; + + &:before{ + content:"n"; + } + } + + .xdsoft_timepicker{ + width: 70px; + float:left; + text-align:center; + margin-left:8px; + margin-top:0px; + + .xdsoft_prev, + .xdsoft_next{ + float:none; + height: 1.5em; + display: block; + text-align:center; + width:100%; + padding:0; + + &:before{ + width:100%; + } + } + + .xdsoft_prev:before{ + content:"e"; + } + + .xdsoft_next:before{ + content:"q"; + } + + .xdsoft_time_box{ + position:relative; + border:1px solid #ccc; + height:170px; + overflow:hidden; + border-bottom:1px solid #DDDDDD; + + > div > div{ + background: #F5F5F5; + border-top:1px solid #DDDDDD; + color: #666666; + font-size: 1em; + text-align: center; + border-collapse:collapse; + cursor:pointer; + border-bottom-width:0px; + height:2.3em; + line-height:2.3em; + + &:first-child{ + border-top-width:0px; + } + } + } + } + + .xdsoft_label{ + display: inline; + position: relative; + z-index: 9999; + margin: 0; + padding: 5px 3px; + font-size: 14px; + line-height: 20px; + font-weight: bold; + background-color: #fff; + float:left; + width:182px; + text-align:center; + cursor:pointer; + + &:hover{ + text-decoration:underline; + } + + > .xdsoft_select{ + border:1px solid #ccc; + position:absolute; + display:block; + right:0px; + top:30px; + z-index:101; + display:none; + background:#fff; + max-height:160px; + overflow-y:hidden; + + &.xdsoft_monthselect{right:-7px;} + &.xdsoft_yearselect{right:2px;} + + > div > .xdsoft_option:hover{ + color: #fff; + background: #ff8000; + } + > div > .xdsoft_option{ + padding:2px 15px 2px 5px; + } + > div > .xdsoft_option.xdsoft_current{ + background: #33AAFF; + color:#fff; + font-weight: 700; + } + } + + } + + .xdsoft_month{ + width:90px; + text-align:right; + } + .xdsoft_year{ + width:56px; + } + .xdsoft_calendar{ + clear:both; + + table{ + border-collapse:collapse; + } + td > div{ + padding-right:5px; + } + td, th{ + width:14.285%; + border:1px solid #DDDDDD; + color: #666666; + font-size: 12px; + text-align: right; + padding:5px 7px; + border-collapse:collapse; + cursor:pointer; + height: 25px; + } + td{ + background-color:white; + } + th{ + background: #F1F1F1; + font-weight: 700; + font-size:0.85em; + text-align: center; + cursor:default; + } + } + + .xdsoft_calendar td.xdsoft_default, + .xdsoft_calendar td.xdsoft_current, + .xdsoft_timepicker .xdsoft_time_box > div > div.xdsoft_current{ + background: $color-orange; + color:#fff; + font-weight: 700; + } + .xdsoft_calendar td.xdsoft_other_month, + .xdsoft_calendar td.xdsoft_disabled, + .xdsoft_time_box > div > div.xdsoft_disabled{ + opacity:0.5; + background:$color-grey-3; + } + + .xdsoft_calendar td.xdsoft_other_month.xdsoft_disabled{ + opacity:0.2; + } + .xdsoft_calendar td:hover, + .xdsoft_timepicker .xdsoft_time_box > div > div:hover{ + color: #fff; + background: $color-teal; + } +} + +.xdsoft_noselect{ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} +.xdsoft_noselect::selection { background: transparent; } +.xdsoft_noselect::-moz-selection { background: transparent; } +.xdsoft_datetimepicker.xdsoft_inline{ + display: inline-block; + position: static; + box-shadow: none; +} + +.xdsoft_scroller_box{ + position:relative; +} +.xdsoft_scrollbar{ + position:absolute; + width:7px; + width:7px; + right:0px; + top:0px; + bottom:0px; + cursor:pointer; + + > .xdsoft_scroller{ + background:#ccc !important; + height:20px; + border-radius:3px; + } +} diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/core.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/core.scss index 60200de208f..bfeb9b62504 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/core.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/core.scss @@ -12,6 +12,7 @@ @import "components/messages.scss"; @import "components/formatters.scss"; @import "components/header.scss"; +@import "components/datetimepicker.scss"; @import "fonts.scss"; diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/vendor/jquery.datetimepicker.css b/wagtail/wagtailadmin/static/wagtailadmin/scss/vendor/jquery.datetimepicker.css deleted file mode 100644 index dad45ed7e13..00000000000 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/vendor/jquery.datetimepicker.css +++ /dev/null @@ -1,304 +0,0 @@ -.xdsoft_datetimepicker{ - box-shadow: 0px 5px 15px -5px rgba(0, 0, 0, 0.506); - background: #FFFFFF; - border-bottom: 1px solid #BBBBBB; - border-left: 1px solid #CCCCCC; - border-right: 1px solid #CCCCCC; - border-top: 1px solid #CCCCCC; - color: #333333; - display: block; - font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif; - padding: 8px; - padding-left: 0px; - padding-top: 2px; - position: absolute; - z-index: 9999; - -moz-box-sizing: border-box; - box-sizing: border-box; - display:none; -} - -.xdsoft_datetimepicker iframe { - position: absolute; - left: 0; - top: 0; - width: 75px; - height: 210px; - background: transparent; - border:none; -} -/*For IE8 or lower*/ -.xdsoft_datetimepicker button { - border:none !important; -} - -.xdsoft_noselect{ - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - -o-user-select: none; - user-select: none; -} -.xdsoft_noselect::selection { background: transparent; } -.xdsoft_noselect::-moz-selection { background: transparent; } -.xdsoft_datetimepicker.xdsoft_inline{ - display: inline-block; - position: static; - box-shadow: none; -} -.xdsoft_datetimepicker *{ - -moz-box-sizing: border-box; - box-sizing: border-box; - padding:0px; - margin:0px; -} -.xdsoft_datetimepicker .xdsoft_datepicker, .xdsoft_datetimepicker .xdsoft_timepicker{ - display:none; -} -.xdsoft_datetimepicker .xdsoft_datepicker.active, .xdsoft_datetimepicker .xdsoft_timepicker.active{ - display:block; -} -.xdsoft_datetimepicker .xdsoft_datepicker{ - width: 224px; - float:left; - margin-left:8px; -} -.xdsoft_datetimepicker .xdsoft_timepicker{ - width: 58px; - float:left; - text-align:center; - margin-left:8px; - margin-top:0px; -} -.xdsoft_datetimepicker .xdsoft_datepicker.active+.xdsoft_timepicker{ - margin-top:8px; - margin-bottom:3px -} -.xdsoft_datetimepicker .xdsoft_mounthpicker{ - position: relative; - text-align: center; -} - -.xdsoft_datetimepicker .xdsoft_prev, .xdsoft_datetimepicker .xdsoft_next,.xdsoft_datetimepicker .xdsoft_today_button{ - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAeCAYAAACsYQl4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDozQjRCQjRGREU4MkNFMzExQjRDQkIyRDJDOTdBRUI1MCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCQjg0OUYyNTZDODAxMUUzQjMwM0IwMERBNUU0ODQ5NSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCQjg0OUYyNDZDODAxMUUzQjMwM0IwMERBNUU0ODQ5NSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkI5NzE3MjFBN0E2Q0UzMTFBQjJEQjgzMDk5RTNBNTdBIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjNCNEJCNEZERTgyQ0UzMTFCNENCQjJEMkM5N0FFQjUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+aQvATgAAAfVJREFUeNrsmr1OwzAQxzGtkPjYEAuvVGAvfQIGRKADE49gdLwDDwBiZ2RhQUKwICQkWLsgFiRQuIBTucFJ/XFp4+hO+quqnZ4uvzj2nV2RpukCW/22yAgYNINmc7du7DcghCjrkqgOKjF1znpt6rZ0AGWQj7TvCU8d9UM+QAGDrhdyc2Bnc1WVVPBev9V8lBnY+rDwncWZThG4xk4lmxtJy2AHgoY/FySgbSBPwPZ8mEXbQx3aDERb0EbYAYFC7pcAtAvkMWwC0D3NX58S9D/YnoGC7nPWr3Dg9JTbtuHhDShBT8D2CBSK/iIEvVXxpuxSgh7DdgwUTL4iA92zmJb6lKB/YTsECmV+IgK947AGDIqgQ/LojsO135Hn51l2cWlov0JdGNrPUceueXRwilSVgkUyom9Rd6gbLfYTDeO+1v6orn0InTogYDGUkYLO3/wc9BdqqTCKP1Tfi+oTIaCBIL2TES+GTyruT9S61p6BHam+99DFEAgLFklYsIBHwSI9QY80H5ta+1rB/6ovaKihBJeEJbgLbBlQgl+j3lDPqA2tfQV1j3pVn8s+oKHGTSVJ+FqDLeR5bCqJ2E/BCycsoLZETXaKGs7rhKVt+9HZScrZNMi88V8P7LlDbvOZYaJVpMMmBCT4n0o8dTBoNgbdWPsRYACs3r7XyNfbnAAAAABJRU5ErkJggg=='); -} -.xdsoft_datetimepicker .xdsoft_prev{ - float: left; - background-position:-20px 0px; -} -.xdsoft_datetimepicker .xdsoft_today_button{ - float: left; - background-position:-70px 0px; - margin-left:5px; -} - -.xdsoft_datetimepicker .xdsoft_next{ - float: right; - background-position:0px 0px; -} -.xdsoft_datetimepicker .xdsoft_next:active,.xdsoft_datetimepicker .xdsoft_prev:active{ -} -.xdsoft_datetimepicker .xdsoft_next,.xdsoft_datetimepicker .xdsoft_prev ,.xdsoft_datetimepicker .xdsoft_today_button{ - background-color: transparent; - background-repeat: no-repeat; - border: 0px none currentColor; - cursor: pointer; - display: block; - height: 30px; - opacity: 0.5; - outline: medium none currentColor; - overflow: hidden; - padding: 0px; - position: relative; - text-indent: 100%; - white-space: nowrap; - width: 20px; -} -.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_prev, -.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_next{ - float:none; - background-position:-40px -15px; - height: 15px; - width: 30px; - display: block; - margin-left:14px; - margin-top:7px; -} -.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_prev{ - background-position:-40px 0px; - margin-bottom:7px; - margin-top:0px; -} -.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box{ - height:151px; - overflow:hidden; - border-bottom:1px solid #DDDDDD; -} -.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div{ - background: #F5F5F5; - border-top:1px solid #DDDDDD; - color: #666666; - font-size: 12px; - text-align: center; - border-collapse:collapse; - cursor:pointer; - border-bottom-width:0px; - height:25px; - line-height:25px; -} - -.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div > div:first-child{ - border-top-width:0px; -} -.xdsoft_datetimepicker .xdsoft_today_button:hover, -.xdsoft_datetimepicker .xdsoft_next:hover, -.xdsoft_datetimepicker .xdsoft_prev:hover { - opacity: 1; -} -.xdsoft_datetimepicker .xdsoft_label{ - display: inline; - position: relative; - z-index: 9999; - margin: 0; - padding: 5px 3px; - font-size: 14px; - line-height: 20px; - font-weight: bold; - background-color: #fff; - float:left; - width:182px; - text-align:center; - cursor:pointer; -} -.xdsoft_datetimepicker .xdsoft_label:hover{ - text-decoration:underline; -} -.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select{ - border:1px solid #ccc; - position:absolute; - display:block; - right:0px; - top:30px; - z-index:101; - display:none; - background:#fff; - max-height:160px; - overflow-y:hidden; -} -.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select.xdsoft_monthselect{right:-7px;} -.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select.xdsoft_yearselect{right:2px;} -.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option:hover{ - color: #fff; - background: #ff8000; -} -.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option{ - padding:2px 10px 2px 5px; -} -.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option.xdsoft_current{ - background: #33AAFF; - box-shadow: #178FE5 0px 1px 3px 0px inset; - color:#fff; - font-weight: 700; -} -.xdsoft_datetimepicker .xdsoft_month{ - width:90px; - text-align:right; -} -.xdsoft_datetimepicker .xdsoft_calendar{ - clear:both; -} -.xdsoft_datetimepicker .xdsoft_year{ - width:56px; -} -.xdsoft_datetimepicker .xdsoft_calendar table{ - border-collapse:collapse; - width:100%; - -} -.xdsoft_datetimepicker .xdsoft_calendar td > div{ - padding-right:5px; -} -.xdsoft_datetimepicker .xdsoft_calendar th{ - height: 25px; -} -.xdsoft_datetimepicker .xdsoft_calendar td,.xdsoft_datetimepicker .xdsoft_calendar th{ - width:14.2857142%; - text-align:center; - background: #F5F5F5; - border:1px solid #DDDDDD; - color: #666666; - font-size: 12px; - text-align: right; - padding:0px; - border-collapse:collapse; - cursor:pointer; - height: 25px; -} -.xdsoft_datetimepicker .xdsoft_calendar th{ - background: #F1F1F1; -} -.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_today{ - color:#33AAFF; -} -.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_default, -.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current, -.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_current{ - background: #33AAFF; - box-shadow: #178FE5 0px 1px 3px 0px inset; - color:#fff; - font-weight: 700; -} -.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month, -.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled, -.xdsoft_datetimepicker .xdsoft_time_box >div >div.xdsoft_disabled{ - opacity:0.5; -} -.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month.xdsoft_disabled{ - opacity:0.2; -} -.xdsoft_datetimepicker .xdsoft_calendar td:hover, -.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div:hover{ - color: #fff !important; - background: #ff8000 !important; - box-shadow: none !important; -} -.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled:hover, -.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_disabled:hover{ - color: inherit !important; - background: inherit !important; - box-shadow: inherit !important; -} -.xdsoft_datetimepicker .xdsoft_calendar th{ - font-weight: 700; - text-align: center; - color: #999; - cursor:default; -} -.xdsoft_datetimepicker .xdsoft_copyright{ color:#ccc !important; font-size:10px;clear:both;float:none;margin-left:8px;} -.xdsoft_datetimepicker .xdsoft_copyright a{ color:#eee !important;} -.xdsoft_datetimepicker .xdsoft_copyright a:hover{ color:#aaa !important;} - - -.xdsoft_time_box{ - position:relative; - border:1px solid #ccc; -} -.xdsoft_scrollbar >.xdsoft_scroller{ - background:#ccc !important; - height:20px; - border-radius:3px; -} -.xdsoft_scrollbar{ - position:absolute; - width:7px; - width:7px; - right:0px; - top:0px; - bottom:0px; - cursor:pointer; -} -.xdsoft_scroller_box{ -position:relative; -} \ No newline at end of file diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html b/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html index 160853aca44..8ec8efa05d8 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/admin_base.html @@ -4,7 +4,6 @@ {% block css %} {% compress css %} - {% endcompress %} From 1683287ee7b5c0780024ecb055513762f8828c34 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 3 Jun 2014 11:15:12 +0100 Subject: [PATCH 060/293] Change wagtailforms SelectDateForm to use DateTimeFields This is because DateFields are not timezone aware which causes warnings to be raised by django. The widgets are still set to "DateInput" so the look and behaviour should not change --- wagtail/wagtailforms/forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wagtail/wagtailforms/forms.py b/wagtail/wagtailforms/forms.py index aaf16eb7925..4f874133a3b 100644 --- a/wagtail/wagtailforms/forms.py +++ b/wagtail/wagtailforms/forms.py @@ -100,11 +100,11 @@ def get_form_class(self): class SelectDateForm(django.forms.Form): - date_from = django.forms.DateField( + date_from = django.forms.DateTimeField( required=False, widget=django.forms.DateInput(attrs={'placeholder': 'Date from'}) ) - date_to = django.forms.DateField( + date_to = django.forms.DateTimeField( required=False, widget=django.forms.DateInput(attrs={'placeholder': 'Date to'}) ) From b35f6d9409e4327d955f0d4b3569f25accdc4a8a Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Fri, 6 Jun 2014 12:52:00 +0100 Subject: [PATCH 061/293] Added test to check that wagtailadmin behaves correctly when LOGIN_URL is not set --- runtests.py | 1 + .../tests/test_account_management.py | 37 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/runtests.py b/runtests.py index 346729653f2..cc9c6e65868 100755 --- a/runtests.py +++ b/runtests.py @@ -103,6 +103,7 @@ WAGTAILSEARCH_BACKENDS=WAGTAILSEARCH_BACKENDS, WAGTAIL_SITE_NAME='Test Site', LOGIN_REDIRECT_URL = 'wagtailadmin_home', + LOGIN_URL='wagtailadmin_login', ) diff --git a/wagtail/wagtailadmin/tests/test_account_management.py b/wagtail/wagtailadmin/tests/test_account_management.py index 0a864aacccf..932ac71a8ef 100644 --- a/wagtail/wagtailadmin/tests/test_account_management.py +++ b/wagtail/wagtailadmin/tests/test_account_management.py @@ -67,7 +67,7 @@ def test_logout(self): """ This tests that the user can logout """ - # Get logout page page + # Get logout page response = self.client.get(reverse('wagtailadmin_logout')) # Check that the user was redirected to the login page @@ -77,6 +77,41 @@ def test_logout(self): # Check that the user was logged out self.assertFalse('_auth_user_id' in self.client.session) + def test_not_logged_in_redirect(self): + """ + This tests that a not logged in user is redirected to the + login page + """ + # Logout + self.client.logout() + + # Get dashboard + response = self.client.get(reverse('wagtailadmin_home')) + + # Check that the user was redirected to the login page and that next was set correctly + self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_login') + '?next=' + reverse('wagtailadmin_home')) + + @unittest.expectedFailure + def test_not_logged_in_redirect_default_settings(self): + """ + This does the same as the above test but checks that it + redirects to the correct place when the user has not set + the LOGIN_URL setting correctly + """ + # Logout + self.client.logout() + + # Get dashboard with default LOGIN_URL setting + with self.settings(LOGIN_URL='django.contrib.auth.views.login'): + response = self.client.get(reverse('wagtailadmin_home')) + + # Check that the user was redirected to the login page and that next was set correctly + # Note: The user will be redirected to 'django.contrib.auth.views.login' but + # this must be the same URL as 'wagtailadmin_login' + self.assertEqual(response.status_code, 302) + self.assertURLEqual(response.url, reverse('wagtailadmin_login') + '?next=' + reverse('wagtailadmin_home')) + class TestAccountSection(TestCase, WagtailTestUtils): """ From 45a10979c67dc35c7e64222192b8c0c9496993e5 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Fri, 6 Jun 2014 12:59:07 +0100 Subject: [PATCH 062/293] Fixed issue with 'django.contrib.auth.views.login' not being reversed properly --- wagtail/wagtailadmin/tests/test_account_management.py | 1 - wagtail/wagtailadmin/urls.py | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/tests/test_account_management.py b/wagtail/wagtailadmin/tests/test_account_management.py index 932ac71a8ef..3553b8fba5b 100644 --- a/wagtail/wagtailadmin/tests/test_account_management.py +++ b/wagtail/wagtailadmin/tests/test_account_management.py @@ -92,7 +92,6 @@ def test_not_logged_in_redirect(self): self.assertEqual(response.status_code, 302) self.assertURLEqual(response.url, reverse('wagtailadmin_login') + '?next=' + reverse('wagtailadmin_home')) - @unittest.expectedFailure def test_not_logged_in_redirect_default_settings(self): """ This does the same as the above test but checks that it diff --git a/wagtail/wagtailadmin/urls.py b/wagtail/wagtailadmin/urls.py index 806240c5c59..819caa92c8f 100644 --- a/wagtail/wagtailadmin/urls.py +++ b/wagtail/wagtailadmin/urls.py @@ -84,6 +84,13 @@ ] +# This is here to make sure that 'django.contrib.auth.views.login' is reversed correctly +# It must be placed after 'wagtailadmin_login' to prevent this from being used +urlpatterns += [ + url(r'^login/$', 'django.contrib.auth.views.login'), +] + + # Import additional urlpatterns from any apps that define a register_admin_urls hook for fn in hooks.get_hooks('register_admin_urls'): urls = fn() From 4b39b7138939a75599a32b2a01b93175723e33cc Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 6 Jun 2014 14:21:47 +0100 Subject: [PATCH 063/293] moved styleguide to a contrib module --- wagtail/contrib/wagtailstyleguide/__init__.py | 0 wagtail/contrib/wagtailstyleguide/models.py | 0 .../templates/wagtailstyleguide}/base.html | 0 .../wagtailstyleguide/views.py} | 6 +---- .../wagtailstyleguide/wagtail_hooks.py | 26 +++++++++++++++++++ wagtail/wagtailadmin/urls.py | 2 -- 6 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 wagtail/contrib/wagtailstyleguide/__init__.py create mode 100644 wagtail/contrib/wagtailstyleguide/models.py rename wagtail/{wagtailadmin/templates/wagtailadmin/styleguide => contrib/wagtailstyleguide/templates/wagtailstyleguide}/base.html (100%) rename wagtail/{wagtailadmin/views/styleguide.py => contrib/wagtailstyleguide/views.py} (81%) create mode 100644 wagtail/contrib/wagtailstyleguide/wagtail_hooks.py diff --git a/wagtail/contrib/wagtailstyleguide/__init__.py b/wagtail/contrib/wagtailstyleguide/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/wagtail/contrib/wagtailstyleguide/models.py b/wagtail/contrib/wagtailstyleguide/models.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html b/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html similarity index 100% rename from wagtail/wagtailadmin/templates/wagtailadmin/styleguide/base.html rename to wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html diff --git a/wagtail/wagtailadmin/views/styleguide.py b/wagtail/contrib/wagtailstyleguide/views.py similarity index 81% rename from wagtail/wagtailadmin/views/styleguide.py rename to wagtail/contrib/wagtailstyleguide/views.py index 68b1941569b..52c5433a1e7 100644 --- a/wagtail/wagtailadmin/views/styleguide.py +++ b/wagtail/contrib/wagtailstyleguide/views.py @@ -5,10 +5,6 @@ from django.contrib import messages from django.contrib.auth.decorators import permission_required -from wagtail.wagtailadmin.userbar import EditPageItem, AddPageItem, ApproveModerationEditPageItem, RejectModerationEditPageItem -from wagtail.wagtailadmin import hooks -from wagtail.wagtailcore.models import Page, PageRevision - from wagtail.wagtailadmin.edit_handlers import PageChooserPanel from wagtail.wagtailimages.edit_handlers import ImageChooserPanel from wagtail.wagtaildocs.edit_handlers import DocumentChooserPanel @@ -41,7 +37,7 @@ def index(request): messages.warning(request, _("Warning message")) messages.error(request, _("Error message")) - return render(request, 'wagtailadmin/styleguide/base.html', { + return render(request, 'wagtailstyleguide/base.html', { 'search_form': form, 'example_form': example_form, }) diff --git a/wagtail/contrib/wagtailstyleguide/wagtail_hooks.py b/wagtail/contrib/wagtailstyleguide/wagtail_hooks.py new file mode 100644 index 00000000000..ae2989be9ca --- /dev/null +++ b/wagtail/contrib/wagtailstyleguide/wagtail_hooks.py @@ -0,0 +1,26 @@ +from django.conf import settings +from django.conf.urls import include, url +from django.core import urlresolvers +from django.utils.html import format_html, format_html_join +from django.utils.translation import ugettext_lazy as _ + +from wagtail.wagtailadmin import hooks +from wagtail.wagtailadmin.menu import MenuItem + +from wagtail.wagtailimages import urls + +from . import views + + +def register_admin_urls(): + return [ + url(r'^styleguide/$', views.index, name='wagtailstyleguide'), + ] +hooks.register('register_admin_urls', register_admin_urls) + + +def construct_main_menu(request, menu_items): + menu_items.append( + MenuItem(_('Styleguide'), urlresolvers.reverse('wagtailstyleguide'), classnames='icon icon-image', order=1000) + ) +hooks.register('construct_main_menu', construct_main_menu) diff --git a/wagtail/wagtailadmin/urls.py b/wagtail/wagtailadmin/urls.py index 6eda643f5ef..1c513629249 100644 --- a/wagtail/wagtailadmin/urls.py +++ b/wagtail/wagtailadmin/urls.py @@ -87,8 +87,6 @@ url(r'^userbar/(\d+)/$', userbar.for_frontend, name='wagtailadmin_userbar_frontend'), url(r'^userbar/moderation/(\d+)/$', userbar.for_moderation, name='wagtailadmin_userbar_moderation'), - - url(r'^styleguide/$', styleguide.index, name='wagtailadmin_styleguide'), ] # Import additional urlpatterns from any apps that define a register_admin_urls hook From 871f4fe37f7a004dd735ae4d6be5887ea7811bc6 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 6 Jun 2014 14:37:05 +0100 Subject: [PATCH 064/293] updated docs --- docs/contributing.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/contributing.rst b/docs/contributing.rst index feb3b96f874..8796fbca8dd 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -17,6 +17,24 @@ Coding guidelines * PEP8. We ask that all Python contributions adhere to the `PEP8 `_ style guide, apart from the restriction on line length (E501). The `pep8 tool `_ makes it easy to check your code, e.g. ``pep8 --ignore=E501 your_file.py``. * Tests. Wagtail has a suite of tests, which we are committed to improving and expanding. We run continuous integration at `travis-ci.org/torchbox/wagtail `_ to ensure that no commits or pull requests introduce test failures. If your contributions add functionality to Wagtail, please include the additional tests to cover it; if your contributions alter existing functionality, please update the relevant tests accordingly. +Styleguide +~~~~~~~~~~ + +Developers working on the wagtail UI or creating new UI components may wish to test their work against the Styleguide, which is provided as the contrib module "wagtailstyleguide". + +To install the styleguide module on your site, add it to the list of ``INSTALLED_APPS`` in your settings: + +.. code-block:: python + + INSTALLED_APPS = ( + ... + 'wagtail.contrib.wagtailstyleguide', + ... + ) + +At present the styleguide is static: new UI components must be added to it manually, and there are no hooks into it for other modules to use. We hope to support hooks in the future. + + Translations ~~~~~~~~~~~~ From 7415f07d2a23da0c3ab318f1b0e294dade27426c Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 6 Jun 2014 14:38:36 +0100 Subject: [PATCH 065/293] updated docs --- docs/contributing.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/contributing.rst b/docs/contributing.rst index 8796fbca8dd..e8e42f1352c 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -34,6 +34,8 @@ To install the styleguide module on your site, add it to the list of ``INSTALLED At present the styleguide is static: new UI components must be added to it manually, and there are no hooks into it for other modules to use. We hope to support hooks in the future. +The styleguide doesn't currently provide examples of all the core interface components, notably the Page, Document, Image and Snippet chooser interfaces are not currently represented. + Translations ~~~~~~~~~~~~ From 38e4e6d361eab61d79c82c760d51173aceac7841 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 6 Jun 2014 14:44:44 +0100 Subject: [PATCH 066/293] added example of iconfield --- .../templates/wagtailstyleguide/base.html | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html b/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html index aa113ede749..0a68ad90c20 100644 --- a/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html +++ b/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html @@ -240,6 +240,8 @@

        Forms

        {% for field in example_form %} {% if field.name == 'file' %} {% include "wagtailimages/images/_file_field.html" %} + {% elif field.name == 'date' %} + {% include "wagtailadmin/shared/field_as_li.html" with input_classes="iconfield icon-date" %} {% else %} {% include "wagtailadmin/shared/field_as_li.html" %} {% endif %} @@ -254,8 +256,6 @@

        Date picker

        Time picker

        - -

        TODO: Rich text

        TODO: page chooser

        TODO: image chooser

        @@ -388,10 +388,7 @@

        Icons

      - -
      - {% endblock %} From 594785d564cec9cc29355707155c9e895739b728 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 6 Jun 2014 14:50:23 +0100 Subject: [PATCH 067/293] removed datepickers, due to be updated in a nearer PR --- .../templates/wagtailstyleguide/base.html | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html b/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html index 0a68ad90c20..e7bd8860611 100644 --- a/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html +++ b/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html @@ -250,17 +250,14 @@

      Forms

    -

    Date picker

    -
    - -

    Time picker

    -
    - -

    TODO: Rich text

    -

    TODO: page chooser

    -

    TODO: image chooser

    -

    TODO: document chooser

    -

    TODO: snippet chooser

    +

    TODO: Date picker

    +

    TODO: Time picker

    +

    TODO: Datetime picker

    +

    TODO: Rich text input

    +

    TODO: Page chooser

    +

    TODO: Image chooser

    +

    TODO: Document chooser

    +

    TODO: Snippet chooser

    @@ -395,9 +392,7 @@

    Icons

    {% block extra_js %} {% endblock %} \ No newline at end of file From b5b4e5dee1926232d2f172008be5ace337735d17 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 6 Jun 2014 15:22:24 +0100 Subject: [PATCH 068/293] removed pre-contrib import --- wagtail/wagtailadmin/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/urls.py b/wagtail/wagtailadmin/urls.py index 1c513629249..e7353420a6f 100644 --- a/wagtail/wagtailadmin/urls.py +++ b/wagtail/wagtailadmin/urls.py @@ -2,7 +2,7 @@ from django.conf import settings from wagtail.wagtailadmin.forms import LoginForm, PasswordResetForm -from wagtail.wagtailadmin.views import account, chooser, home, pages, tags, userbar, styleguide +from wagtail.wagtailadmin.views import account, chooser, home, pages, tags, userbar from wagtail.wagtailadmin import hooks urlpatterns = [ From 81e37bbf7cf69c0d29e9bfd52897e29175788942 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 6 Jun 2014 15:30:24 +0100 Subject: [PATCH 069/293] pep8 space --- wagtail/wagtailadmin/urls.py | 1 + 1 file changed, 1 insertion(+) diff --git a/wagtail/wagtailadmin/urls.py b/wagtail/wagtailadmin/urls.py index e7353420a6f..8fbf2f6e770 100644 --- a/wagtail/wagtailadmin/urls.py +++ b/wagtail/wagtailadmin/urls.py @@ -89,6 +89,7 @@ url(r'^userbar/moderation/(\d+)/$', userbar.for_moderation, name='wagtailadmin_userbar_moderation'), ] + # Import additional urlpatterns from any apps that define a register_admin_urls hook for fn in hooks.get_hooks('register_admin_urls'): urls = fn() From cf3d6a4e66b646bf666b73fa0b16f9f2f5418c5b Mon Sep 17 00:00:00 2001 From: Jeffrey Hearn Date: Fri, 6 Jun 2014 10:58:14 -0400 Subject: [PATCH 070/293] Addition of attrs property to image template tag --- wagtail/wagtailimages/models.py | 6 ++++++ wagtail/wagtailimages/tests.py | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/wagtail/wagtailimages/models.py b/wagtail/wagtailimages/models.py index 24fd1f0bf18..921f65921bf 100644 --- a/wagtail/wagtailimages/models.py +++ b/wagtail/wagtailimages/models.py @@ -225,6 +225,12 @@ class AbstractRendition(models.Model): def url(self): return self.file.url + @property + def attrs(self): + return mark_safe( + 'src="%s" width="%d" height="%d" alt="%s"' % (escape(self.url), self.width, self.height, escape(self.image.title)) + ) + def img_tag(self): return mark_safe( '%s' % (escape(self.url), self.width, self.height, escape(self.image.title)) diff --git a/wagtail/wagtailimages/tests.py b/wagtail/wagtailimages/tests.py index 00d1245e646..f36751650d8 100644 --- a/wagtail/wagtailimages/tests.py +++ b/wagtail/wagtailimages/tests.py @@ -183,6 +183,18 @@ def test_image_tag(self): self.assertTrue('height="300"' in result) self.assertTrue('alt="Test image"' in result) + def render_image_tag_as(self, image, filter_spec): + temp = template.Template('{% load image_tags %}{% image image_obj ' + filter_spec + ' as test_img %}') + context = template.Context({'image_obj': image}) + return temp.render(context) + + def test_image_tag_attrs(self): + result = self.render_image_tag_as(self.image, 'width-400') + + # Check that all the required HTML attributes are set + self.assertTrue('width="400"' in result) + self.assertTrue('height="300"' in result) + self.assertTrue('alt="Test image"' in result) ## ===== ADMIN VIEWS ===== From 5936c020d8099e8d3f8a54df1f2ef6520296d938 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Fri, 6 Jun 2014 16:28:51 +0100 Subject: [PATCH 071/293] Added I18N to new datetime picker --- .../static/wagtailadmin/js/page-editor.js | 52 +++++++++++++++---- .../wagtailadmin/pages/_editor_js.html | 2 + .../shared/datetimepicker_translations.html | 29 +++++++++++ .../wagtailforms/index_submissions.html | 14 ++++- 4 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 wagtail/wagtailadmin/templates/wagtailadmin/shared/datetimepicker_translations.html diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js index 0d6c4d51f1b..83024b732e8 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js +++ b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js @@ -54,23 +54,55 @@ function insertRichTextDeleteControl(elem) { } function initDateChooser(id) { - $('#' + id).datetimepicker({ - timepicker: false, - format: 'Y-m-d', - }); + if (window.dateTimePickerTranslations) { + $('#' + id).datetimepicker({ + timepicker: false, + format: 'Y-m-d', + i18n: { + lang: window.dateTimePickerTranslations + }, + lang: 'lang' + }); + } else { + $('#' + id).datetimepicker({ + timepicker: false, + format: 'Y-m-d', + }); + } } function initTimeChooser(id) { - $('#' + id).datetimepicker({ - datepicker: false, - format: 'H:i', - }); + if (window.dateTimePickerTranslations) { + $('#' + id).datetimepicker({ + datepicker: false, + format: 'H:i', + i18n: { + lang: window.dateTimePickerTranslations + }, + lang: 'lang' + }); + } else { + $('#' + id).datetimepicker({ + datepicker: false, + format: 'H:i', + }); + } } function initDateTimeChooser(id) { + if (window.dateTimePickerTranslations) { + $('#' + id).datetimepicker({ + format: 'Y-m-d H:i', + i18n: { + lang: window.dateTimePickerTranslations + }, + language: 'lang' + }); + } else { $('#' + id).datetimepicker({ - format: 'Y-m-d H:i', - }); + format: 'Y-m-d H:i', + }); + } } function initTagField(id, autocompleteUrl) { diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html index b8334eae27c..3ddb8c1f36a 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/_editor_js.html @@ -27,6 +27,8 @@ {% hook_output 'insert_editor_js' %} {% endcompress %} +{% include "wagtailadmin/shared/datetimepicker_translations.html" %} + {% comment %} Additional js from widgets media. Allows for custom widgets in admin panel. {% endcomment %} diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/shared/datetimepicker_translations.html b/wagtail/wagtailadmin/templates/wagtailadmin/shared/datetimepicker_translations.html new file mode 100644 index 00000000000..cdbc9863883 --- /dev/null +++ b/wagtail/wagtailadmin/templates/wagtailadmin/shared/datetimepicker_translations.html @@ -0,0 +1,29 @@ +{% load i18n %} + + diff --git a/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html b/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html index 9b5ca941f2c..ae957229521 100644 --- a/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html +++ b/wagtail/wagtailforms/templates/wagtailforms/index_submissions.html @@ -3,15 +3,25 @@ {% block titletag %}{% blocktrans with form_title=form_page.title|capfirst %}Submissions of {{ form_title }}{% endblocktrans %}{% endblock %} {% block bodyclass %}menu-snippets{% endblock %} {% block extra_js %} + {% include "wagtailadmin/shared/datetimepicker_translations.html" %} + From 004b90d9cf54532a0f1d30f25001872c790ae814 Mon Sep 17 00:00:00 2001 From: Ben Margolis Date: Fri, 6 Jun 2014 10:03:32 -0700 Subject: [PATCH 072/293] send init_new_page signal when creating a new page in the admin --- wagtail/wagtailadmin/signals.py | 3 +++ wagtail/wagtailadmin/views/pages.py | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 wagtail/wagtailadmin/signals.py diff --git a/wagtail/wagtailadmin/signals.py b/wagtail/wagtailadmin/signals.py new file mode 100644 index 00000000000..53a135584e5 --- /dev/null +++ b/wagtail/wagtailadmin/signals.py @@ -0,0 +1,3 @@ +from django.dispatch import Signal + +init_new_page = Signal(providing_args=["page","parent"]) \ No newline at end of file diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index 69e6b7f4f43..f86306ae8c7 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -10,7 +10,7 @@ from wagtail.wagtailadmin.edit_handlers import TabbedInterface, ObjectList from wagtail.wagtailadmin.forms import SearchForm -from wagtail.wagtailadmin import tasks, hooks +from wagtail.wagtailadmin import tasks, hooks, signals from wagtail.wagtailcore.models import Page, PageRevision, get_page_types @@ -124,6 +124,7 @@ def create(request, content_type_app_name, content_type_model_name, parent_page_ # return redirect('wagtailadmin_pages_select_type') page = page_class(owner=request.user) + signals.init_new_page.send(sender=create,page=page,parent=parent_page) edit_handler_class = get_page_edit_handler(page_class) form_class = edit_handler_class.get_form_class(page_class) From de678ac8ba5312952ec90a4e89ef57cbf216d196 Mon Sep 17 00:00:00 2001 From: Robert Clark Date: Fri, 6 Jun 2014 14:40:05 -0400 Subject: [PATCH 073/293] add next and previous published siblings to Page model --- wagtail/tests/fixtures/test.json | 30 ++++++++++++++++++- wagtail/wagtailcore/models.py | 15 ++++++++++ .../wagtailcore/tests/test_page_queryset.py | 18 +++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/wagtail/tests/fixtures/test.json b/wagtail/tests/fixtures/test.json index 11b82d9f169..8e316ffd882 100644 --- a/wagtail/tests/fixtures/test.json +++ b/wagtail/tests/fixtures/test.json @@ -39,7 +39,7 @@ "model": "wagtailcore.page", "fields": { "title": "Events", - "numchild": 3, + "numchild": 4, "show_in_menus": true, "live": true, "depth": 3, @@ -186,6 +186,34 @@ } }, +{ + "pk": 9, + "model": "wagtailcore.page", + "fields": { + "title": "Ameristralia Day", + "numchild": 0, + "show_in_menus": true, + "live": true, + "depth": 4, + "content_type": ["tests", "eventpage"], + "path": "0001000100010004", + "url_path": "/home/events/final-event/", + "slug": "final-event", + "owner": 3 + } +}, +{ + "pk": 9, + "model": "tests.eventpage", + "fields": { + "date_from": "2015-04-22", + "audience": "public", + "location": "Ameristralia", + "body": "

    come celebrate the independence of Ameristralia

    ", + "cost": "Free" + } +}, + { "pk": 1, "model": "tests.formfield", diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index 30ffc8a77f4..3b90e9c0e92 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -649,6 +649,21 @@ def get_descendants(self, inclusive=False): def get_siblings(self, inclusive=True): return Page.objects.sibling_of(self, inclusive) + def get_next_published_sibling(self): + next_sibling = self.get_next_sibling() + + while next_sibling and not next_sibling.live: + next_sibling = next_sibling.get_next_sibling() + + return next_sibling + + def get_prev_published_sibling(self): + prev_sibling = self.get_prev_sibling() + + while prev_sibling and not prev_sibling.live: + prev_sibling = prev_sibling.get_prev_sibling() + + return prev_sibling def get_navigation_menu_items(): # Get all pages that appear in the navigation menu: ones which have children, diff --git a/wagtail/wagtailcore/tests/test_page_queryset.py b/wagtail/wagtailcore/tests/test_page_queryset.py index 06f2c3e21c3..3db3bd5f8fd 100644 --- a/wagtail/wagtailcore/tests/test_page_queryset.py +++ b/wagtail/wagtailcore/tests/test_page_queryset.py @@ -254,3 +254,21 @@ def test_not_type(self): # Check that the homepage is in the results homepage = Page.objects.get(url_path='/home/') self.assertTrue(pages.filter(id=homepage.id).exists()) + + def test_published_next(self): + events_index = Page.objects.get(url_path='/home/events/') + current_page = Page.objects.descendant_of(events_index).live().first() + + # All pages must be live + while current_page: + self.assertTrue(current_page.live) + current_page = current_page.get_next_published_sibling() + + def test_published_prev(self): + events_index = Page.objects.get(url_path='/home/events/') + current_page = Page.objects.descendant_of(events_index).live().last() + + # All pages must be live + while current_page: + self.assertTrue(current_page.live) + current_page = current_page.get_prev_published_sibling() From 9b17154cdf5c3770c7f5c44140952c21f759db27 Mon Sep 17 00:00:00 2001 From: Jeffrey Hearn Date: Thu, 5 Jun 2014 21:46:24 -0400 Subject: [PATCH 074/293] Added wagtail and django settings doc more settings stuffs settings stuff settings stuff so many things omg is it really two AM More docs --- docs/building_your_site/djangodevelopers.rst | 17 + .../building_your_site/frontenddevelopers.rst | 3 +- docs/editing_api.rst | 4 +- .../new_pages/inserting_videos.rst | 5 +- docs/form_builder.rst | 3 + docs/images/screen_wagtail_redirects.png | Bin 0 -> 19260 bytes docs/index.rst | 1 + docs/settings.rst | 615 ++++++++++++++++++ docs/wagtail_search.rst | 3 + 9 files changed, 647 insertions(+), 4 deletions(-) create mode 100644 docs/images/screen_wagtail_redirects.png create mode 100644 docs/settings.rst diff --git a/docs/building_your_site/djangodevelopers.rst b/docs/building_your_site/djangodevelopers.rst index b4899d70f3e..46e24b08fec 100644 --- a/docs/building_your_site/djangodevelopers.rst +++ b/docs/building_your_site/djangodevelopers.rst @@ -1,9 +1,15 @@ For Django developers ===================== +.. contents:: Contents + :local: + .. note:: This documentation is currently being written. +Overview +~~~~~~~~ + Wagtail requires a little careful setup to define the types of content that you want to present through your website. The basic unit of content in Wagtail is the ``Page``, and all of your page-level content will inherit basic webpage-related properties from it. But for the most part, you will be defining content yourself, through the construction of Django models using Wagtail's ``Page`` as a base. Wagtail organizes content created from your models in a tree, which can have any structure and combination of model objects in it. Wagtail doesn't prescribe ways to organize and interrelate your content, but here we've sketched out some strategies for organizing your models. @@ -269,6 +275,7 @@ not_type(self, model): return self.get_query_set().not_type(model) +.. _wagtail_site_admin: Site ~~~~ @@ -278,3 +285,13 @@ Django's built-in admin interface provides the way to map a "site" (hostname or Access this by going to ``/django-admin/`` and then "Home › Wagtailcore › Sites." To try out a development site, add a single site with the hostname ``localhost`` at port ``8000`` and map it to one of the pieces of content you have created. Wagtail's developers plan to move the site settings into the Wagtail admin interface. + + +.. _redirects: + +Redirects +~~~~~~~~~ + +Wagtail provides a simple interface for creating arbitrary redirects to and from any URL. + +.. image:: ../images/screen_wagtail_redirects.png diff --git a/docs/building_your_site/frontenddevelopers.rst b/docs/building_your_site/frontenddevelopers.rst index e5f58339799..83dbb9e6cfe 100644 --- a/docs/building_your_site/frontenddevelopers.rst +++ b/docs/building_your_site/frontenddevelopers.rst @@ -1,7 +1,8 @@ For Front End developers ======================== -.. contents:: +.. contents:: Contents + :local: ======================== Overview diff --git a/docs/editing_api.rst b/docs/editing_api.rst index c0637002600..60698a74ac2 100644 --- a/docs/editing_api.rst +++ b/docs/editing_api.rst @@ -346,9 +346,9 @@ The ``RelatedLink`` class is a vanilla Django abstract model. The ``BookPageRela For another example of using model clusters, see :ref:`tagging` -For more on ``django-modelcluster``, visit `the django-modelcluster github project page`_ ). +For more on ``django-modelcluster``, visit `the django-modelcluster github project page`_. -.. _the django-modelcluster github page: https://github.com/torchbox/django-modelcluster +.. _the django-modelcluster github project page: https://github.com/torchbox/django-modelcluster .. _extending_wysiwyg: diff --git a/docs/editor_manual/new_pages/inserting_videos.rst b/docs/editor_manual/new_pages/inserting_videos.rst index 038f3e4274b..1b32c0d1c5a 100644 --- a/docs/editor_manual/new_pages/inserting_videos.rst +++ b/docs/editor_manual/new_pages/inserting_videos.rst @@ -1,3 +1,6 @@ + +.. _inserting_videos: + Inserting videos into body content ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -9,4 +12,4 @@ As well as inserting videos into a carousel, Wagtail's rich text fields allow yo .. image:: ../../images/screen21_video_in_editor.png -* A placeholder with the name of the video and a screenshot will be inserted into the text area. Clicking the X in the top corner will remove the video. \ No newline at end of file +* A placeholder with the name of the video and a screenshot will be inserted into the text area. Clicking the X in the top corner will remove the video. diff --git a/docs/form_builder.rst b/docs/form_builder.rst index 9aa220e1970..a141cc3768a 100644 --- a/docs/form_builder.rst +++ b/docs/form_builder.rst @@ -1,3 +1,6 @@ + +.. _form_builder: + Form builder ============ diff --git a/docs/images/screen_wagtail_redirects.png b/docs/images/screen_wagtail_redirects.png new file mode 100644 index 0000000000000000000000000000000000000000..516bdd046551da4edeed93935626850ed0899ca8 GIT binary patch literal 19260 zcmch<1zcOpx;D-(yQKnUSMUNAT#Gxjn^GFINT7IIJh(g5fZ}Z+xD1_bi(3_4FJz;vh})brazmpz^!q-74sGumgpjQ3Pv=~Opt^bI#C;9# z)kr3rOa?m?8Q

    7kSG;EfRf!iOTkI`cWJ8#g4dNzF5e!J6Nl{SnoYu**l$e*tK0} zs+rh36T1yG66nqS%h{KobR z`S4Da{P&+-`bUrYCsG&#?(%+#;ZkAtw9wdjg*on?&3Q_ea52u3a3UhYmm=lz*}i#i zcb)epQ2I*b?F$6?@?X7}m=kd%Ns2yFDhf*RZUGG(pdo~;v>iVSjFBEmX-+eK_Rzx9 z97nh^uRpmT-jPPE7yo_R{$kLEnKM4Tj0+aDQ4W_ayV|_+Au(6?4cI*JB?W7F$Gj&Y}louFAgI^4^Rc&T+vW7z}`=-LI%h)8Vi+2S3+ia)|BDJUk!zGk#31`gs1 z-dMJAfC!jEe*QZzZdO=E(+716ELLb$F^S7@J&tmuXO*31dtQ*~Gt}y^HB;Q7<^M$K z&^Vz$BO@Q`;$L;VZ(D!=gnI5)((Vi^DPnnR3`N`QoK17sV(LDPo7NT;_=F(e61R;|`~ByQ zSz9t51H&GrvIMprYYZ=ZB)q3k2` zw&xWw#U58PmJ)8lic0R#7B=S4E-UqkpgA=AaxcYOGhz=8f9r?sm32r>RWW}F9`m$l zTh8wDjvp^hS~h#3AWYU9zp<^0#^0s!=i^lARXpBs>WMAyh!A^HUt$@AkB3hquFas?wds)fr9bpHKLz%llF$_A9y3;7HA`+TJ!2adgAR~&KG+zDs~;;pEhna%r?uWZhJL-6xXes z7kJvfbE#hGMg5wRULh^=s`yFwO{dyrsevHUa^S*+q87&wI#V&lfJ{cQHG(Z$NW$?e z^X{(3JJMs$78(9oY|K{7or4_RY-%M^EqroZ`)%6{!(T%ZU23;M(6R;n6RK>6lhMM$ z>w;2ychhv1=P&M(;HvEPZ)^woy%9#tDVC-?Ykg-Sbf-TUV=d>RYS zNUP(^0Saew$A%fuy!X#$wIo8*N)kRoa|qXt8O4P*!=IS zY-{A|R9;({e@`MsD$27Q8`EhfmvP^CEOH-^L-DSye-Ckpc9^y}%~3a8E5W~D&bfi& zQG*IC57`F2yS*;M>b#n8Gn){hC*k+0^)B~Pb1lb7rw_edC!XsG)VL>ez~w@~CGy+B zfP;>8oHiW9?>57+w8j$ld65!1C%5XF&FzW}jT+vJ*zMjMK8^XcyZTYbr_EHWiiIyo zj)m|&ZtBS+SpX7VHGESz>Y6U6FWlne+gbTW>tJp=%K8yg$gP3#1l0#>!59uNKQw3c zG5sJcY0x_Ks5@;aPnlIAWPEQ#nX`Dd5)I#QIZ@!289n$qp-_ll8W9)fe5_Z{i=*w; zUqbI)_C0Cb+?n>NI^H1(moc@F*9y|S4;h;^uoF#4mHP6D5J8LJ*sN!g%{ctgpI3lL zfBxsp;y10I!ndN2!{=HEKO3fNSYxZC|NMUc*Tx$^f&Bkt zME(n`|F=^9WDEbAT}%i`2>o{PS03^_rg(mP)bD>sFaBLI|B&DO+a%`isLwxq)c?$) zUWxESuTw~E`O3RD5SLa~^2l7#()7`zcLMZLT{hdvW#4Ka-2Uyk55=1@^CmbBXAl$h z{zJc`L0H5I_n7Z#e=gZ6?RK{Xxb1;( z64BYqzbRGLYbn_@B-8KL-{slj&P}&oy9F%EzQRlNQNWk>>CNBRUYB>RdUuN3Uk@eM zLu%KZ*cw`CBaZ{FRq0`#EP>P)HT+|la9>OY zy6PPJsc90!X=USjgUschYU{y_LY)D9nqz^tjF}b|yn?Gg^gbzbEWIAypPp(^)IRRp+e{d1EYx0j|#+ zf}Bz=yNe|xR;$5Q-wLa*lK4gvkSo!B>tY^N-XTr5X44YT&Blr#nwBeXzv)O}I|9sH zON7k|NpxT2eAbjZC4>bv5wWLjpHCL+8q>kU25YrAXMFvPqu#;k-C3IgFMKwtz+g6Q zDdLB&01)w<2L z76UK~DOYha2lM&kM}Yro6VIgciK~`EYh?Ex<&@ zJKP&dEV*3BVPq|aTOtu(TtzsJ=6WGU-48gJ1Vx$Cz}3#Lth?R4_Eah$VZ^&W%DKau zI$PC8H?0$9;-hyx^SK}MDiZyPW-3{M6@2}Cb*50q;#8&10)3Obr3;I3(UJt)C$X)} ztfT4Ng=4s~^dSdLIa~qECXu2=WKgzz=?D0#PLmRg`IN~o?p>lrj z#eyR0Sin%0k+!WIasH58oVdQdU#JPLtFWr{wh@<0Y2@LOb`aR5*pO zWrj|0tblbZt$AV3nM0baQU?4z1O3ucqD8yKmNqkbbA;OHJTL$k<7$#eid*|=l$Ucd z4v7WSDjwEG9^nB6^l z)A6jbtMB$ApXu#2W{VU(o_>FR#7)nJcPr$|$$^sa3=bLA*3Rv%?8!gwHb%r4(YFWb zr+Moao9QM9f+a!j66%$ruoR|4VFfVn?lY!RZzIm)%_7L}7VDGn;w#f-mh7GEjz-mG z*5IQ0qocbfvv$twbfm_yj|Yk$ioPd24`Jp9-!L}!(9CD%Y)^!LFG{l~BIZ)R$(mvW znqQK60?;|9O&um}20kKB9eTxmk5@1> zk_5r~=i1y8l9F;c<-!i=`@ST?k`XF^ntIq0XU#7qY)D|bQnmD;vQf0dhW09p(`dP= zpI=?ah`xu%7Xi0og956fN;xM305!a^UT6>pxf<%gP}sRHO35TLZ`wBhr}87^qdUWN`oaWbK!ApV6PbE$47zrCYn%QBL{CMeH?Y}j7P_0 zl|y$=j2bKME0qOq*wAMwVuz{XM}BMA5o-6ZMBa-5 z_o!!|{wNN+P-vyupA&P065~FdOReVOBk;AS2FCl`2cUprw7B*Bxz`ld6dZ+^;)P;8 zUh=!U;JG;}LvXAXsTrFl>;MJ-;d1!5*}%U;pk6m<0leVYT=-99J~l_*y?gg!+~;RD zl4-N+3!i=i#4aT54R9I>(0{#mKM^>bmzA4s@{D*1T$#84P=J^#zgkJAwapyHUHSFg zFW!{57nZOHh?5ie`KWXXmnQU!RSpkuuVwo9G7NYSaQjUb7R2Us+nj>**L!_bac%c% zMoN2nv?77AxZkSs=+Tdt<4EP@> zeJpK!V+My8#vXdho{DhEhO$t_3j!7jtC^|**^ zyPs_u)6~7ZSKN5~$Jhyxx%&f$Z9Y7;L07-2BXTQ&wO%geW2G7=tb0ohT4SJ+Vz1Uo zL>>-{(#_cL2s**|%(AoQ{{nCC?goQ=i7LMFgu*VAcz(V$kF8TNBw%#Zp>#C=&2f6) zIws*`JklwgwJC`KB89YVP++-K*h`7(H*E$TEF)&)2cI@RwYRtL7}e)@ambIXz$7G^ z3FH}D_8P9)L@?jgCW0i>1%s}3Zn(;7j*n`gwoAT!OXv4sY zG6)|;(O^F@0dy5BllOf`z&gM8L%Nsj{;2V)+s;Da_9w~pBB+Rj`l49$7jJwb&rtsT zqfr+Y^Qszv5KwE`pb8y=4HDf4N=55f;XWXDZ0AGY#xFm8ihCL6zf|P3ZGhk01IE1- z`Xj(CePhF!-zSheQ-Q>9vC_b$`#!yiF%ztv zRWpTW2$$+V4osLS#b)=pto%C&3X1Fy=%4H;^ELrz);vvPNr#s?VTak)4N^9Df?;zl z>ZP+CCbdR1YsOgVe51=Xy(d*Kbc4;a6Akni>STFEd~(&?EtNe4{u75i?o;2qeI@q9 zD5=c!4%xy4X0W!K9Cjhms+?Cs%);TaJDqSbQHQ&b;{Z+?g|_+kPPw;pJ1n@+Tho>4 zJZ@a94+G$nF1^*NidPM45}~F|tz}zf!db`RMZD%{7-Uo)xu*~BnO!F8Bhkj<{DWmV zQ`TZ?G>Tcn;Y0JM!wXrU&0@k`sjGqyuKzU?RP&BkSYbA8yPIiGiz;o3Hx>nq0&J8W zB6Hq|XhJ~-mP&4jqj{Y#XG}4oBn+*KQ-lE>)w-4q9X$`8Eq_=Ofoj-n{f)tT#l`9C zy2qK*^SpC2onBSO8KO}WWT*Al=_Y}WM83488Ba2bB5ANY)d;YTuFr2QOslaM>NxFN zbxYg3^&9coeB-N&9)@!}{y|M|>^(HCU56l$K=d6({JEJ}zwvCcdIex|8|qOdN_r)U zA1w9-mGNP2aMtM2R0-vy533~!s?sG~!`3=)M`Hp|&7ZUkY+>+>n%v&UgcXD0p8QtU zPMFV+yM!o|FxtSuaMd8!W?`|WGofuC3_P3Sgi)#5K+0T3ZqH$QN}muN16TCd$4Xpf zTHS^@vmP8d7Z^F9oZKP>+!2#@`KeC)q@^B}iqS2_w1mcrr%|i)AR!6yS`LIt#h;K> z@}1`@IZ#1y!oqOz*K-NKd`Q`HohIkuVoVk(@6PG%!b=&@2&l-KgZ zs^}egGm-$Gu1>$0|6FK>tS=sqK_umfUXmtl<9 z%Du``s-Y_Q?owzD1IjC)SgV>?Ha%589%EBV1p$09b^XITZ5B9Olh;$9O|5%KDANlk5B;#Fw0mYa78+Jp|mz z8A7ixR@}a)o@RI>KCnBYPP6U&(G(3ydIzUsEuVRJ`w71FR;ir>iuzuVU<2oTzR4fx zuqDfkquLeQvB3bry@AahiC=280I)l3SGXhw`&2Wt^(1l=LE2~WFFlTyufN+O*cVB6 zCE@u7qH2kz$-U?yD^z^d?PPgLW@|4UC$A@?Erc0;c3x?fU#7VB*Tt7@Dpl3Y3F+4g zt1l$U%9ldKZ0%a~uD~WPdB`d&oh)UZMGATE&)SptUu^0bOL9MkT4<{7Le@Xh+vhyA zseH(AvRlTlfnFw@$-gkKi67V@eOX#8)@|n(REu)xo4kOwIlZr^iAK=mUS-3c?b0<7 zCO#gsZnarE5SI=jomgtGDkC!V_vX@MPm9%U)vEcudqfqg?mr}+(c3kYt!vZsjF9H~ zAOvqyId#SU3Yt#mk`{_p(il}G3EkF+Z^&8{YC7n6hz(bS#F^A;A;ew=oOZrkIMNvb zHMs?)fz}PluF&y=N>!`83f1`~1q@7wmNB^|L4x=06=VgW&VnYwW~&ePc1uk4dYQij|iQL%}MOA1L3>xVvRoAswAHft=i?JdCAM*J6! z>@BJmhYOtGO8W(|froX+0qTRIJ}CwQ(Rw2k^ZDiy9ldx|uFL4q{BcTCuanyq)Jv7r z;X?(XVP|=p0V=px$b8l>)en0~wazA?UOfPxm+ zOD<`OJnb=m7%V-om8E0z6Use@R?zMAJ1~m zP!08M4VcE!=CiF2b(xSosn+cTpf z>{|Zkh@{Ju=;H?A0(`=xhz#rDL=wE~VR-#_H@Q{{fJ0DnYhJAMF zIlNHz%@yLa_-G>ktHNs*dIA=o8N{w7h?b}48QWN%ke{r^;}w0)l+YytR~`4e2@ecw zToz96L;7vgdX#>x_QdiHt|gXP@{E!ejRu+%ueAnBtxz^4j;J;@%hL~4)Zc$f?zA#uCj5Q@~AcyvEUcmPmY~cmbQJ{ zx^c{;k@-_x$fxP4!*Lq@W!LJ}+splC7}s7Se1>HpS^mwi;RV|)X7?a}XPA;>Z8h<6 zy`+@KPaXHm9zHmBB(1(|m#;tb^Wl``YvH4&SD}8aOkacPahrN&adMKYqCr_w7Y`Wx6%_we738rX9ajp2!zuId^orcIDSVcBYBd#cqojogMLpH|)PL-*ke>%D$Oa z`KPWA}n_9^%|;|9Iv`DbOa|{yZZ$)Wfo2eIe9PIBsdoPklXO^T+cKrh=@I+dkdn+N@zZ4G-51 z_7;ww42qWQ9u85tFp5ZcyuKdWn3Iuz1@-(z{oMDIfRkY9s`spU-IHZ;7WnEQi<7kw z#kWgGBUJu^HS7LNFIQ4;9OjKZui`&cvrA)fF4GdZP&u>5GX&#bdTN!W92{1km0B5Y zaQ4uVFPRhI6+d$Udes#mGwT4gEyMK3obVxDBL}rB;CeXB4!;Y09H;* z_-zEY=V$$cw77(}$V}uH9m%z33>_XFtXh#wPYUyHW{g;dXRBtErY_j)gy%V!IkFsj zSta9JKQ<~J!Sd=3qP*Ovy_@K3G)A4{VR@Lf^w=o-@=EXu%^Czsc{!5 zcfmtjY7ZEzhg_WIeMdURU2I30buWWm>{+e%=|})%d+(O_LC}ennHus&%)FISH?{j9 zN%ogLDX(M<2`gMxHF`hfj8(j|&oWsLy)5%t{w)q8pAc+OQ}ALiyL5@JY3z>&y~s2K zqn~Hsk+xTT)`3gCH>LB)SQ8NK4jUPJ{&F7Dl9&Q1Mi?B7#rWGgzrIZ0N;ACss%inz zErZwgwEnRyHYA!Exg5}34PT{Pp$z*{W7}&_O-X}hGtQs}#Vxyi(tMDL zd0PaEohGJ(`mFiv`EU&p7NdD76_H!~ou$}{hr#-Oz--6odDtEN ze7)kq$*B&aThpx5ndE2xejanJuFTuX4Q(O%edkbh!xee&TfJoL1WD%EhNM}7(FN^J z8g~Df;bzG}kHqoZ+UmWXcKdeNA5Yu8lU|O=l!;*!KaMwRh}0YnJsR?TakVcgxvryg zce(F$8WL}nDXH488Sd3c8oty$oz#V~;XB0a)n~~;Ikr(KbEWO{VC^hpjCi;F7I6h> zLD_RdO7Dh}ANokpp_Igpb+?|_y^yMUN}o{z*Bjy43%Je7pdk9JR8(De#2#F;uUbeO z_Jrw}^#w8XmVsb6#+?0Vg63rBh%<#Qsp7%Gfya!DUjbgpB@7(ZJe_F+%o_x||5g5+qf%=}Iv5Ui>I&P8+L4nIDo( z&_PTKwT!PVZKRh)5~jP>A$^;Dr&BKQ0ejANHnGo&5`%|3PtN1)Z(uh;3(l(-@pAUinSY+qK+7+O4-TSiO(^h;=sn`e^&}Dksf-?Gbwz+E4e2 zZGoM07te0MC$L&?KVIFuzqPbKG8P04Dv;QRhJ9Rndj~}D7#na)Q*QT%#-x8gwAot<~75_~_f)_S>h>d`z{|#C_#%M%IO; znat%x1r6GK_6~D5Un=Z9ajyI&HflL8CG;DijYiobu683%OxY7<>f($yh_hg26;TVA zDxQcEKO`208D}}1#DOx4f81-sPHF3YeS)8}L0Z@BH;PXjY!~c~Kg`Wdjjj2SdP*{% zbbE&XSPQ(u?`6H`{qtTRV_O9=+PW{Tw0iJes{y3B6q=^J7!wqdMjmanOSsUqn+T5M zX5wi1k!jPn>|$Ic+2cAAr}@ss^!9HTp8^KW<5X2rKBw$Ui)=b3H_;zR96V!qGq_rE zy!>0?TC3vtyJ|isVf%p!8l{Wd-BD5|S(0E_!h+|nHtKFm*By70>I1jcDYewihCK$kQq!NI>DtuymTET}oxv@Vnsq0<^41>5lJTnGdyTz0@zdV>{E4xeoFYQ@FOd)bPBPT}R@7fM5PMHoa8-JV-trStKIwh6 zvqBO5&!+(%Fjg*`vP|QeXP3ezt=h!=3y*{9juXgM-Cn^HHHvpAR(uas8|C;-l+zcE zYMRNLx?Z;MGTb850DYZaDc{=TWnOi>|1|6^eD7D=D3e;#xWKJ~*pQ`x6zFPXMx}&ql?F7^ev@hImgoN<2xo!f~5w_>7k_?$O%YLZVN3UK^*1g?U{1Tb@!yI4%X{#MnJ0@2_t+RLar$p&7Y0THp{)(cc& z_xKcE;wt8AcnAVjw+Qf3)giJK3=Fc5ys}2c3a&4!6eQ{+Ui3}4rN{KsJ759ZE}j#7 zmRu&|HpenY3OsD?sU6lg9{7zqIg?*^OXa}&>4}`nVv`sf6Ezf(uk04wJ}vtf+t45F zN~vJ8X8EgIbgHUZaZ0T{*hoP!tgd0{Ruc=UXY?GMy!*7(T;BRJ_p+{kRlh-%8B$81 zZ+m%;?=c(e_^DpTniisIF7Y8-HQB|y#@KkDijfa(0X1^ty^@fnq?#FTJ0tR_V`BZO z>O!c@oV~|QqUW==1`G63Qk$@s>CTVmRUHB#r$R9Cdis}Je*uCf@+TnVJK%nT0Sk-@ zNIY};o}v2u{jgRNWc~}+0nLSW7hJk^9DnO=>s~)~}`}M(@ zkZJAhnh{nU>e8i4#BGh_`wwq$Yu%~}KB=fSXiL}1Xc+zSxW1)8E4gT85kvY;N&A!< z@Q)WnlfCR66r(>@y%BYFGAoO#-VGeZ#l;|2R@PK`zl!E97&6)y?TtUxv=uTRtQ-$~ z=4KAM5Cj`?_HjU8-)-o61A4LOdWTU ziyx?&fYtG?t-%1%u|4qSA#xcVeQTBh28VlbBu#@G)S*Z-#c`gpSbX-DS%bd8xS}X# zGV}5W@@P-GaR44{BSC0yaeXAwxCWAR>ziW-kL5ahG8F8&Z`Kr0qHz$BTXXquK5bPi z+23xHU)9%XFS7gk*fl@)#5u<1iLPZnygn?s8jmR9(I#X!#52ht^mPd(Wec-j2?!ox zv7LshVa%to&3+R^PM0caq0tdG7@!d#nq--BzFRqjcbw>%OE#PL8U zIr$Cw+YbPp{M@m&1`YoW7`90iphvM2Su;k)a*V%g0H<8r80->@JR5n3$87Ays?Ne&4OT%q62g z|KU2O@+Q(BY=B>!@Nl4mnU+;W+!DA)cbn$I+Y*E21;M;Zvvpj?0MdAL3$)e#iNL$) zuh^5zaJv7x0)6y;j;X#t0m*QtUr0FXyw{O=yFJ8wwoq$Ps%%2_Lh~lQ!eQSx|1F0( z2lgCl*%;L}ttMoWiG22W+k)!2mSJoiSooG=f!;MPBM#6s?87mullIE=fo5-;F{!Z9 zc!#J8!{DbgGP0|wZ&>$(5AME9$k@_Ukn#GR(a99I8InGLyyYZ|L~NPCq7xT~k5|Jz z(P4e$MB%T~L}Zz7ox4vBqMwO67^mWpK*#?-`qd@06T;tEMqVBl0y{Sv#tz5}5{Qhg zx z`whCY-_^UV5By7NwXgwKe|)So2(tcC)ODS;Y~|1dSS0iikGFc*s#4=L#?F4x-%W** zxU@4%Hm6mmThFXn5i$k%R;4`Xx~8G&yS$!GS>z?C{M)YO{z>$)O8Cp>V#7)_GqpBb zp}G97?McI=j)ENaH=KAgj&^6AVM>2Xp`k$a$(BXp$n9c1-S1WkBVvua(kj`WK;<4~0OfAM}bcz(4!GHUXEQ4xGhd*d@Xas#wZ>q}pa1A^Qz9a>dAkv#!Xp&?Pq)DaCE zB<*BMsE2CXwhxOH8|hgs^50?pW(Ei0#%NWqR+RJyLi@yL2Ior!`{7fU>#X$*Uc7c+ z)qxXHYA=YMp&W}q5S3XexG^U;*TsZAkaga3Ox%oi*9Tv+{l@$lBd74yv`}#`Rl)>{ zoNnyVenLGaxWd#WV4ztS_)stdBcTv&zZRE~&)pq@8}9Jv&^pvMKCa?Tz24up)s`kM zOuAN@InW@IwahL{FJjhEpar`dyEqYgQ-MY9Y3;Ipr!D)kvT{kV_=^e2z%>tu2=|Uf z*8L+O_yGjk!XN!iD4;Vobo-f65NHyX<5*l#tfggGDbBB#V&-$)xC#L$MALX1fw>K* zb+D*8UPS|U>|m%HzC3Q0wpu_HU%{tOOlN1V9_CZ61VwD(r?T+NSNOSh(}nm%R3x!K z2+xXB=K@>W)Vn2MkOU4B2)hq!zPIYzQK-0OF>c0&Z*2J~ozJcCJOKF&5a4Uq-crT< z`0<2^I#*oC{ZosD5{KAM*Yt!KwZ;E&z8?)EpJw|(=o4arjs|NGCQ335dkZvLe&*$wWzy;Q!;t# zG9X1>yeHV2s`gBTz{o>ZSDf9prHt$c9vSBJZzh3T6P?E5)1S;;9G`Al5{6xBeyrLh zxR3XZoR6p=l33yp87VKOGrtDOO#?EtgxgxMsBVCo4qnYqcTlL1oXyy zOn*Y>yl1sXD%+9>a%6Sj;L@eYsEaPCLW#T>)Q*W{w}RIrB@fhc|IB?^H$w4vpqq-V zaC4zG`}wyM=g-@lt>I$ORLb=VO>$W-PJIE zulby81w@$KgjoEelfJDw^W!u(5o7No6Ac0@?b?>5(QrF2{s46`>t& z&Q9iD&VSmT6OV4vB0{W)V~{fY@2rVY&9WxcISsJqwq8q0ky9P-YE^y zt>!&OE-`w_0j~;Ru3x8FS=rpw|6m2U{xh+EzL$rQ&*Ra%(O{*}+8D(>-yPVc8{|YJ zz)q_55NuvoY}!aV>zikzZK>7#vN^7G34R%8(`K4N^672r4M<;st}Awp`L|l zb5~e>OS9;UHx-52hNqOYy1<=4Qj4o?I2qd~3>tjGO8p(c2`L4r=qf(`k-Ww(AlD$D zR}TFMT#D!VGuPmjb;0?NtUr?twl1*fY)?9M^tL}WUf3g^&BBU}pu>MAKdv1Z7UxyS zNQeAqwgKGRo1Fdu5Lvk-q;X4&L}W)YQXeq`m;2e0wn<>G3 zna4rml%bY!1`0k;y@VPP>755t53=Qys|D!j^E%;wCLTs!@LS!kveT(|>|thohBoD_ zGH+jf+N2Iem|y*w)B7sm$xKtNF0ax^p<$(E{@h7NkYhOW^3|ex300YLU45H~tA^g1 z1Rxz1aL-QYdpRMtVkF$vbeGhCnDYl-Y<5L1vU9PLkCW4!t4#=odm>tZa5Z^t!^D{s z)Reex_q65p1v*C)xEXR-A7RuHZ988-lA=-2P~imh_0|x$g7eZW8!JnL>9IDnP?vz@%^W1!ZA?;KPw5UO76_|J(5-(@AN%-({Z)~iESMde_#iFMehI1MVj2a zimMHXsOYqP5){9^qgN<@VqlnSD%z2F_|Cg2q4XK(A4Tw&{13ZE#>#vf06U;3Ocsm9 z78lGFU0pRV1P9!LPQfZY(2_!0ui)3NTc{C?fjBPocC- z)p0!=>#8O^{H|PS4LU_}3s|UMU%IYSM+IX># zkM;eVbU>>=C*K5J^4|b$VG%hc8e=m&#dQX%wBSzesJZ#!OR>NmfMIEw$!o;#L*D^z zRE1IbARa@lJ_>TGJ6y)w+1m(6kiA&9Uyg>)uH>AF$82$`&NU_(85uVz0h=*8>izo}D+D$P_8>s#I!GrSha)3fQUY+2O zKc|o`=c5HU7zW<~Dw*uN@~`t;ga#^R6=-G1a^bUV*^v5&~JCEQWy-#0lxhYPRG-;RicGs z2I)oHq|509<)T~R^Ehn#^@cxWZ_7kU24EaE#2m_LGY}xvq~Xo^Cc4qdAACO8vbB~{syJ~ z@_1$bW8kF6*!Jmh^SlC7$vJ2jq_2 zW;6VlqSt^K7=R{b-bm4as`07@m<$Zyl5WKB(vq*c+}C4TaWbNAn$4K(p9z}2w% zv^T3~Kesb%eO0Gibl6{zd@;8(xf8OT#>9vSs=W5$kOwHaTa7Yv*n7gIoGJ3qawK9A~Eyjph4BT^2 z_)9pvOa!+zzIFVpU>>47{w!;W5YcrLu9uRcPSPzmkf@&9W@TM;E(J{v#B_EY3HkKb z>m{`w*5}DXZP{15zr9^o3a|N~+o}dqc2JcyUXI^-mKkK_k||(@dU`;RKin_Ym+;A} zYUcBp#mH3exjyEnSzK^19i^jGR?n7BnS33=0kU*al{{$th2k@f!-?8xQTZtq#>0{8 z#w>vYq>0b;9OUAqnc05=h2vI294)F1IWaM`^IzK9#CCRkcjfOVXS+kit`m>^jBE|^B}RM5WbbY3gZ7W48q1KlTgjw(Iu zc;cctX%whDY72KGi)%{vf)eFCeC>&vGW%Vdo-S%!REO>^XV0{h4m{O}0T|a%344v<9~rM<%O6D@6O zo1(#_X85E)wWXeSu(|9xV6hz6rU=@;EN9WfcyaXJf~b2zQwE-O0KRb9xY3aHeBqSL z9+TNk4Q^17s|QEQsrtHr&~xH|6fc5~2R*Zsgf)H{V|?UT`(7T#rEYXhsJ%}qANl2Z9)d`wws zof=U6ntWtaGDi6Z(=DO=Cdlm@Ah_|-fcf$_K;unqS{5uK&XRM}GP_P_71I_cUq@?H z3AS_&(1l2_63(8gLWG2>QVVV(_1}Z>a*#U`N#?iwV#*aeSVnJ_=?58tnH18AC(0?B zX0p5M>e`lGk7-wX0<`Ptg*0G6$R%-wzK^Ndwqhc_ce&{?BBgR^daIRyTqzV?K({4n zw@GG5N5jUVE4xkGnhWG*=CK5|@)sqHW$y0gXW{0=C2$4s0uc$2=;q7Ei9$5#Y)lQY zm9d75XU3LT!8nNo48t0S7;IpsixXg~U1o+{=8dLa%9yF48{e3WjQ3`KxN<@B$__5u zvc{(j_}awh1>5fKpc0WY{S*|J%gO&2ps=o-ON@O2@#OM|e`Td&`}aye@4KM#dqLd; zfcE=7-6qA3+3h<;8E{rAQw@YbxCpp-vu-e`bs!`}dv|Rlsi`3Va}avu;n)cM-BMc? z=m1CD*ht3M*xKmX{yr7Usj;QRP98!L)QSmlvGw;47$A6Sdn+lVsKIsdwbBxvQ=3$n zk&*Z@<$H#;dP_$F_&>xNj2YU3cTV$H7ueNxVRL2*hRtK;*&;0*DZZk#>vA8OXm@AR zW@#%XX%?3p>NiX@+j_+51N+E2IyfEcZF82{%2CNA>ndGnBbk5nBjQ#gQpO8>L*`^E zN=89f4Lm)MG1dcmTrt1!#dFY*(_=P)FNWYT^E_3lZvxNeuzo{z>w!a1WJ=HX{YM3e zw1Ix(_}?!RsvSbs90a&hdiM7{b@dv*GOpK{I@P1A#l1V2*oCkzYg{~8s!a}=LrT)Mx0{rZOZIo$rB zr>r=HrCC=i$&{9?rK{1_ z>^!~-0MyhqAu*$lq3@n>NGgWZce>)>k$a1R;u)`oNhoJQ={X8l1%qW2wrb4(KTz(! zVB7J1m^-S06Hw`d0JwYqG=N`bfsH<{OA2vj`}WIPBuHa;QbxLa9#DVE4a|?r zFDppyf{96b3RsKJ2gY{YWm}YW_Lz^48SrWf8-RD3aO5dj*hCt z^;j2dog(cImz3s03)j>&q2zU5TfPLZawgVy#sWrc?cnIBDX!Fno6W^h!rty#<1@FN z#q5N{H|6d&Jd`&;x*C?>V7zA!xZ&l+`)ta06Va2DY%>Olv zhGlDa#AO6nIgLnQXJq~}fwB%Ki-#Bk1g0Lr?Nyki<(H?lHy$J|A>omdX)YT-h~jUk zW*FP6a-v<;Uf#GTqu_b_#O$qK$tuyd?T}q#uiPieY1D%wyhb6bsUgn#F3E49?)6S8 z+W#9reUyyPnrTmlToMh734UVXrlM&g=s2EqLt7!Cte{@s+FRsS z6v>`=fR*2Vw2nn;m#lW3D#UWus0xtZGg8l96CmH*nD*Q#p{;ujjsPNBa z{jI{^&i)@Z?!Pj{f84lNV9OJ=;bb&3Yq$EWyLrG717eP*adpmQpw7#It#(^WRg8jS zUzf}-gde9t)@z0+q017#2O)vJ??F8i(}K^Lh*E>QgZhJhf#xw#lh7294_fhhAL#Y z^NK@5@qUW@CSha?|82Z8wl`RaC}kl&c#t*Md$wrdzLc~p`;#p5NCj>6$XAqpm_H-2 zZ%JXc4<5N$df&7W^Vt+-VR84di5E1fAgLl}!nZ+l<6V6Y+kU7?T;P;#XLg;WNsVKB zsY_;iC(NqtxQ;q_K5IM4rE3Jhw$C&zC~T)bon+q9YH{FRj0IOpuSq3FM#9WUzM*z- zM29-B3->?^_w5*S=48Y~n)B zq=mI@)7yLdb~EiqH}Y)*S?;JDQjFVwtIFf}(C zw7tv}So*RJupFk`REir@(fd8<`B|DQP>8K{xy1|@Bb)ckD zY12Kq#Csm6-PEvo4}9Wq;9ZAGuWjT!PD;(s?;y3cie=!0uoieUCOkW`7tA|;coKG; zs&Ez9Ge%*$?R$PcWE0Z7Ni^J!A+cacCW4D+OjiKJF$Hw&nz_mo38-9>YLu9Q&W&1aG2 z&JVc6Ct7WXm#m%n#u8bx1O&|5p8bgJHrXofNIO_O9v&^vztd8zYhG7GHSSxQP}veT z8q_&Jxn0Q=ObYZqZpGac&a42ESX?PR<~BvaHI6-o#>NcjX_56Al2qrxAv#zXIb*oR zora&CJ@cI=+82RzQ#vL>q-NtJ89cVADrK?`j`z7|8&6ZT=N%VG>PcqxbL9aCKI7yb zj^6&M$V%SP9K4-B4aTBV#+&!lW9@)O-+M7k-r4m(>7hT>RU1oZnAdW}@68okAxwojd~*X)e$_u9RFlaj!Bs-|@+KhL82`@j;`$(7de+x(PD& zdBnMnGsC2&V7;f|RyQz-Rc*SzLNbZj`b z7ybTsZRY=I(!Xxpe^b~SA(kim`?XC#*FS?#Xs>csnjO&8c>!N3Kq^{~%6@ Date: Mon, 9 Jun 2014 10:04:33 -0400 Subject: [PATCH 075/293] made published siblings a single query --- wagtail/wagtailcore/models.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index 3b90e9c0e92..1864f5c88b3 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -650,20 +650,10 @@ def get_siblings(self, inclusive=True): return Page.objects.sibling_of(self, inclusive) def get_next_published_sibling(self): - next_sibling = self.get_next_sibling() - - while next_sibling and not next_sibling.live: - next_sibling = next_sibling.get_next_sibling() - - return next_sibling + return self.get_siblings().live().filter(path__gt=self.path).order_by('path').first() def get_prev_published_sibling(self): - prev_sibling = self.get_prev_sibling() - - while prev_sibling and not prev_sibling.live: - prev_sibling = prev_sibling.get_prev_sibling() - - return prev_sibling + return self.get_siblings().live().filter(path__lt=self.path).order_by('-path').first() def get_navigation_menu_items(): # Get all pages that appear in the navigation menu: ones which have children, From 85793d3dbb3f5687efe9659ef7d0ced3c0f7e832 Mon Sep 17 00:00:00 2001 From: Jeffrey Hearn Date: Mon, 9 Jun 2014 11:47:12 -0400 Subject: [PATCH 076/293] Settings doc changes based on feedback --- docs/settings.rst | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index c6e9a4fc0e5..018af5d0154 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -25,7 +25,7 @@ From your app directory, you can safely remove ``admin.py`` and ``views.py``, si .. _Django Settings: https://docs.djangoproject.com/en/dev/topics/settings/ -.. _Django URL Dispatcher:https://docs.djangoproject.com/en/dev/topics/http/urls/ +.. _Django URL Dispatcher: https://docs.djangoproject.com/en/dev/topics/http/urls/ What follows is a settings reference which skips many boilerplate Django settings. If you just want to get your Wagtail install up quickly without fussing with settings at the moment, see :ref:`complete_example_config`. @@ -161,7 +161,7 @@ Authentication .. code-block:: python - LOGIN_URL = 'wagtail.wagtailadmin.views.account.login' + LOGIN_URL = 'wagtailadmin_login' LOGIN_REDIRECT_URL = 'wagtailadmin_home' These settings variables set the Django authentication system to redirect to the Wagtail admin login. If you plan to use the Django authentication module to log in non-privileged users, you should set these variables to your own login views. See `Django User Authentication`_. @@ -243,7 +243,7 @@ Email Notifications WAGTAILADMIN_NOTIFICATION_FROM_EMAIL = 'wagtail@myhost.io' -Wagtail sends email notifications when content is submitted for moderation, and when the content is accepted or rejected. This setting lets you pick which email address these automatic notifications will come from. +Wagtail sends email notifications when content is submitted for moderation, and when the content is accepted or rejected. This setting lets you pick which email address these automatic notifications will come from. If omitted, Django will fall back to using the ``DEFAULT_FROM_EMAIL`` variable if set, and ``webmaster@localhost`` if not. Other Django Settings Used by Wagtail @@ -271,18 +271,6 @@ For information on what these settings do, see `Django Settings`_. .. _Django Settings: https://docs.djangoproject.com/en/dev/ref/settings/ -URL Configuration (urls.py) -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There's one more setting that must be included in ``settings.py``: - -.. code-block:: python - - ROOT_URLCONF = 'myproject.urls' - -This setting bootstraps your project's URL patterns and views into the Django server. The root urlconf will include URL patterns for Wagtail and any URLs for your own app functionality (developed external to Wagtail). - - Search Signal Handlers ---------------------- @@ -292,7 +280,7 @@ Search Signal Handlers wagtailsearch_register_signal_handlers() -This loads Wagtail's search signal handlers, which need to be loaded very early in the Django life cycle. While not technically a urlconf, this is a convenient place to load them. +This loads Wagtail's search signal handlers, which need to be loaded very early in the Django life cycle. While not technically a urlconf, this is a convenient place to load them. Calling this function registers signal handlers to watch for when indexed models get saved or deleted. This allows wagtailsearch to update ElasticSearch automatically. URL Patterns @@ -437,7 +425,7 @@ settings.py ) # Make this unique, and don't share it with anybody. - SECRET_KEY = 'wq21wtjo3@d_qfjvd-#td!%7gfy2updj2z+nev^k$iy%=m4_tr' + SECRET_KEY = 'change-me' # List of callables that know how to import templates from various sources. TEMPLATE_LOADERS = ( @@ -505,7 +493,7 @@ settings.py ) # Auth settings - LOGIN_URL = 'django.contrib.auth.views.login' + LOGIN_URL = 'wagtailadmin_login' LOGIN_REDIRECT_URL = 'wagtailadmin_home' # A sample logging configuration. The only tangible logging From e6008ccaee626d44138c8d58a7ec667af1a5b84b Mon Sep 17 00:00:00 2001 From: Ben Margolis Date: Mon, 9 Jun 2014 11:24:19 -0700 Subject: [PATCH 077/293] fix kwarg spacing --- wagtail/wagtailadmin/views/pages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index f86306ae8c7..5f0da8d009e 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -124,7 +124,7 @@ def create(request, content_type_app_name, content_type_model_name, parent_page_ # return redirect('wagtailadmin_pages_select_type') page = page_class(owner=request.user) - signals.init_new_page.send(sender=create,page=page,parent=parent_page) + signals.init_new_page.send(sender=create, page=page, parent=parent_page) edit_handler_class = get_page_edit_handler(page_class) form_class = edit_handler_class.get_form_class(page_class) From a3b4bcb558df5ec28c343e9cb2eca04c539a7635 Mon Sep 17 00:00:00 2001 From: Ben Margolis Date: Tue, 10 Jun 2014 04:15:35 -0700 Subject: [PATCH 078/293] only send signal outside if not POSTing new page --- wagtail/wagtailadmin/views/pages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index 5f0da8d009e..b7a85dcedc7 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -124,7 +124,6 @@ def create(request, content_type_app_name, content_type_model_name, parent_page_ # return redirect('wagtailadmin_pages_select_type') page = page_class(owner=request.user) - signals.init_new_page.send(sender=create, page=page, parent=parent_page) edit_handler_class = get_page_edit_handler(page_class) form_class = edit_handler_class.get_form_class(page_class) @@ -173,6 +172,7 @@ def clean_slug(slug): messages.error(request, _("The page could not be created due to errors.")) edit_handler = edit_handler_class(instance=page, form=form) else: + signals.init_new_page.send(sender=create, page=page, parent=parent_page) form = form_class(instance=page) edit_handler = edit_handler_class(instance=page, form=form) From 546f18cbb565750eee5747bdf24a1777dd97c2f0 Mon Sep 17 00:00:00 2001 From: Ben Margolis Date: Tue, 10 Jun 2014 18:53:43 -0700 Subject: [PATCH 079/293] Adding basic documentation for the image_formats feature. --- docs/editing_api.rst | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/docs/editing_api.rst b/docs/editing_api.rst index c0637002600..88fc9458f5e 100644 --- a/docs/editing_api.rst +++ b/docs/editing_api.rst @@ -371,8 +371,8 @@ Edit Handler API ~~~~~~~~~~~~~~~~ -Hooks ------ +Admin Hooks +----------- On loading, Wagtail will search for any app with the file ``wagtail_hooks.py`` and execute the contents. This provides a way to register your own functions to execute at certain points in Wagtail's execution, such as when a ``Page`` object is saved or when the main menu is constructed. @@ -547,6 +547,38 @@ Where ``'hook'`` is one of the following hook strings and ``function`` is a func hooks.register('insert_editor_css', editor_css) +Image Formats in the Rich Text Editor +------------------------------------- + +On loading, Wagtail will search for any app with the file ``image_formats.py`` and execute the contents. This provides a way to customize the formatting options shown to the editor when inserting images in the ``RichTextField`` editor. + +As an example, add a "thumbnail" format: + +.. code-block:: python + # image_formats.py + from wagtail.wagtailimages.formats import Format, register_image_format + + register_image_format(Format('thumbnail', 'Thumbnail', 'richtext-image thumbnail', 'max-120x120')) + + +To begin, import the the ``Format`` class, ``register_image_format`` function, and optionally ``unregister_image_format`` function. To register a new ``Format``, call the ``register_image_format`` with the ``Format`` object as the argument. The ``Format`` takes the following init arguments: + +``name`` + The unique key used to identify the format. To unregister this format, call ``unregister_image_format`` with this string as the only argument. + +``label`` + The label used in the chooser form when inserting the image into the ``RichTextField``. + +``classnames`` + The string to assign to the ``class`` attribute of the generated ```` tag. + +``filter_spec`` + The string specification to create the image rendition. For more, see the :ref:`image_tag`. + + +To unregister, call ``unregister_image_format`` with the string of the ``name`` of the ``Format`` as the only argument. + + Content Index Pages (CRUD) -------------------------- From eb70c215e94791cd212e5d2e7509a9c0bc0dfb2a Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 11 Jun 2014 09:48:07 +0100 Subject: [PATCH 080/293] Added test for wagtailstyleguide --- runtests.py | 1 + wagtail/contrib/wagtailstyleguide/tests.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 wagtail/contrib/wagtailstyleguide/tests.py diff --git a/runtests.py b/runtests.py index 6fd37ebeb84..022c1b50365 100755 --- a/runtests.py +++ b/runtests.py @@ -84,6 +84,7 @@ 'wagtail.wagtailsearch', 'wagtail.wagtailredirects', 'wagtail.wagtailforms', + 'wagtail.contrib.wagtailstyleguide', 'wagtail.tests', ], diff --git a/wagtail/contrib/wagtailstyleguide/tests.py b/wagtail/contrib/wagtailstyleguide/tests.py new file mode 100644 index 00000000000..71f8f6e7627 --- /dev/null +++ b/wagtail/contrib/wagtailstyleguide/tests.py @@ -0,0 +1,15 @@ +from django.test import TestCase +from django.core.urlresolvers import reverse + +from wagtail.tests.utils import login + + +class TestStyleGuide(TestCase): + def setUp(self): + login(self.client) + + def test_styleguide(self): + response = self.client.get(reverse('wagtailstyleguide')) + + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailstyleguide/base.html') From 6eec08dfbe1ea0718618bef2b8c51ab7e14628f8 Mon Sep 17 00:00:00 2001 From: Helen Warren Date: Wed, 11 Jun 2014 11:51:33 +0100 Subject: [PATCH 081/293] Fix behaviour described in issue 77. Specifically validate that for an editors pick a search term/phrase must be defined and at least one valid page recommendation specified. --- wagtail/wagtailsearch/forms.py | 19 ++++++++++++++ .../wagtailsearch/editorspicks/add.html | 2 +- wagtail/wagtailsearch/views/editorspicks.py | 25 +++++++++++++------ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/wagtail/wagtailsearch/forms.py b/wagtail/wagtailsearch/forms.py index 03e4ecd45d6..9485e4619e1 100644 --- a/wagtail/wagtailsearch/forms.py +++ b/wagtail/wagtailsearch/forms.py @@ -31,6 +31,8 @@ class Meta: class EditorsPickFormSet(EditorsPickFormSetBase): + minimum_forms = 1 + minimum_forms_message = _("Please specify at least one recommendation for this search term.") def add_fields(self, form, *args, **kwargs): super(EditorsPickFormSet, self).add_fields(form, *args, **kwargs) @@ -40,3 +42,20 @@ def add_fields(self, form, *args, **kwargs): # Remove query field del form.fields['query'] + + def clean(self): + # Editors pick must have at least one recommended page to be valid + # Check there is at least one non-deleted form. + non_deleted_forms = self.total_form_count() + non_empty_forms = 0 + for i in xrange(0, self.total_form_count()): + form = self.forms[i] + if self.can_delete and self._should_delete_form(form): + non_deleted_forms -= 1 + if not (form.instance.id is None and not form.has_changed()): + non_empty_forms += 1 + if ( + non_deleted_forms < self.minimum_forms + or non_empty_forms < self.minimum_forms + ): + raise forms.ValidationError(self.minimum_forms_message) diff --git a/wagtail/wagtailsearch/templates/wagtailsearch/editorspicks/add.html b/wagtail/wagtailsearch/templates/wagtailsearch/editorspicks/add.html index 3c927d96c6c..f443d1a6a77 100644 --- a/wagtail/wagtailsearch/templates/wagtailsearch/editorspicks/add.html +++ b/wagtail/wagtailsearch/templates/wagtailsearch/editorspicks/add.html @@ -6,7 +6,7 @@ {% include "wagtailadmin/shared/header.html" with title=add_str icon="pick" %}

    - {% blocktrans %}s + {% blocktrans %}

    Editors picks are a means of recommending specific pages that might not organically come high up in search results. E.g recommending your primary donation page to a user searching with a less common term like "giving".

    {% endblocktrans %} {% blocktrans %} diff --git a/wagtail/wagtailsearch/views/editorspicks.py b/wagtail/wagtailsearch/views/editorspicks.py index 97332818e0e..bb39c02baed 100644 --- a/wagtail/wagtailsearch/views/editorspicks.py +++ b/wagtail/wagtailsearch/views/editorspicks.py @@ -45,12 +45,12 @@ def index(request): def save_editorspicks(query, new_query, editors_pick_formset): - # Set sort_order - for i, form in enumerate(editors_pick_formset.ordered_forms): - form.instance.sort_order = i - # Save if editors_pick_formset.is_valid(): + # Set sort_order + for i, form in enumerate(editors_pick_formset.ordered_forms): + form.instance.sort_order = i + editors_pick_formset.save() # If query was changed, move all editors picks to the new query @@ -72,10 +72,14 @@ def add(request): # Save editors picks editors_pick_formset = forms.EditorsPickFormSet(request.POST, instance=query) - if save_editorspicks(query, query, editors_pick_formset): messages.success(request, _("Editor's picks for '{0}' created.").format(query)) return redirect('wagtailsearch_editorspicks_index') + else: + if len(editors_pick_formset.non_form_errors()): + messages.error(request, " ".join(error for error in editors_pick_formset.non_form_errors())) # formset level error (e.g. no forms submitted) + else: + messages.error(request, _("Recommendations have not been created due to errors")) # specific errors will be displayed within form fields else: editors_pick_formset = forms.EditorsPickFormSet() else: @@ -95,15 +99,22 @@ def edit(request, query_id): if request.POST: # Get query query_form = forms.QueryForm(request.POST) + # and the recommendations + editors_pick_formset = forms.EditorsPickFormSet(request.POST, instance=query) + if query_form.is_valid(): new_query = models.Query.get(query_form['query_string'].value()) # Save editors picks - editors_pick_formset = forms.EditorsPickFormSet(request.POST, instance=query) - if save_editorspicks(query, new_query, editors_pick_formset): messages.success(request, _("Editor's picks for '{0}' updated.").format(new_query)) return redirect('wagtailsearch_editorspicks_index') + else: + if len(editors_pick_formset.non_form_errors()): + messages.error(request, " ".join(error for error in editors_pick_formset.non_form_errors())) # formset level error (e.g. no forms submitted) + else: + messages.error(request, _("Recommendations have not been saved due to errors")) # specific errors will be displayed within form fields + else: query_form = forms.QueryForm(initial=dict(query_string=query.query_string)) editors_pick_formset = forms.EditorsPickFormSet(instance=query) From 0faad897b8d45075b7d3e610f49c72150f68044c Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 12 Jun 2014 16:00:31 +0100 Subject: [PATCH 082/293] updated font to include new padlock symbols --- .../wagtailadmin/scss/components/tabs.scss | 13 +- .../scss/fonts/wagtail-icomoon.json | 226 +++++++++--------- .../wagtailadmin/scss/fonts/wagtail.eot | Bin 26032 -> 26120 bytes .../wagtailadmin/scss/fonts/wagtail.svg | 6 +- .../wagtailadmin/scss/fonts/wagtail.ttf | Bin 25868 -> 25956 bytes .../wagtailadmin/scss/fonts/wagtail.woff | Bin 15080 -> 15144 bytes 6 files changed, 121 insertions(+), 124 deletions(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss index 984766b04f3..cd805186288 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss @@ -15,8 +15,7 @@ } a{ @include transition(border-color 0.2s ease); - @include box-shadow(inset 0px -2px 3px 0 rgba(0,0,0,0.1)); - background-color:$color-grey-4; + background-color:lighten($color-teal-darker, 3%); outline:none; line-height:3em; text-transform:uppercase; @@ -25,19 +24,17 @@ text-decoration:none; display:block; padding:0 20px; - color:$color-grey-2; - border-top:0.3em solid $color-grey-4; + color:white; + border-top:0.3em solid $color-teal-darker; border-bottom:1px solid transparent; &:hover{ - color:inherit; - border-top-color:$color-grey-2; + color:white; + border-top-color:$color-teal-dark; } } a.errors{ - color:$color-red !important; - &:after{ @include border-radius(50px); @include box-shadow(1px 2px 2px rgba(0, 0, 0, 0.1)); diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json index fead2733b81..12ad185e509 100755 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json @@ -4,13 +4,57 @@ { "icon": { "paths": [ - "M102.030 101.608v819.555h819.555v-819.555h-819.555zM352.717 791.689h-165.288v-85.398h301.65v85.398zM792.109 360.562h-604.678v-128.099h603.303v128.099zM790.731 591.965h-603.303v-128.099h603.303v128.099z" + "M516.006 87.25c-130.903 0-237.403 106.496-237.403 237.403v135.587c0 1.54-1.902 4.136-3.396 4.634-12.837 4.283-23.263 7.99-32.808 11.672-11.381 4.388-19.967 17-19.967 29.34v311.543c0 12.255 8.53 24.881 19.841 29.363 87.506 34.676 179.604 52.253 273.734 52.253s186.229-17.582 273.737-52.258c11.306-4.482 19.831-17.103 19.831-29.358v-311.543c0-12.342-8.585-24.953-19.971-29.345-9.548-3.68-19.976-7.391-32.804-11.672-1.49-0.497-3.39-3.095-3.39-4.634v-135.587c-0.001-130.903-106.498-237.399-237.401-237.399zM451.344 600.775c0-35.736 28.951-64.658 64.657-64.658 35.707 0 64.658 28.917 64.658 64.658 0 23.68-13.355 43.507-32.328 54.745v106.901c0 17.869-14.46 32.328-32.33 32.328-17.869 0-32.328-14.46-32.328-32.328v-106.901c-18.974-11.239-32.328-31.065-32.328-54.745zM671.777 324.648v116.988c-51.081-10.989-103.489-16.558-155.749-16.564-52.236 0-104.636 5.568-155.796 16.55v-116.975c0-85.892 69.876-155.771 155.771-155.771s155.777 69.878 155.777 155.772z" ], + "width": 1044, "grid": 0, "tags": [ - "form" + "lock39 copy" ] }, + "properties": { + "order": 3, + "id": 67, + "prevSize": 32, + "code": 109, + "name": "lock39copy", + "ligatures": "" + }, + "setIdx": 0, + "iconIdx": 0 + }, + { + "icon": { + "paths": [ + "M788.176 475.115c-9.548-3.68-33.476-12.002-33.819-12.278-28.021-6.998-84.009-22.628-84.009-22.628-51.081-10.989-103.489-16.558-155.749-16.563-50.758 0-101.661 5.275-151.442 15.65l-77.844-77.846c-60.737-60.735-60.737-159.555 0-220.292s159.558-60.739 220.296-0.003l80.945 80.942c27.277-6.612 57.773-20.055 77.184-41.624-1.559 0.162-3.675-0.317-4.527-1.165l-95.875-95.875c-92.566-92.559-243.175-92.559-335.738 0.003-92.562 92.562-92.565 243.174 0 335.739l44.75 44.753c-12.177 4.076-22.199 7.649-31.381 11.191-11.381 4.388-19.967 17-19.967 29.34v311.543c0 12.255 8.53 24.881 19.841 29.363 87.506 34.676 179.604 52.253 273.734 52.253s186.229-17.582 273.737-52.258c11.306-4.482 19.831-17.103 19.831-29.358v-311.546c0.001-12.342-8.584-24.953-19.97-29.345zM546.904 654.092v106.901c0 17.869-14.46 32.328-32.33 32.328-17.869 0-32.328-14.46-32.328-32.328v-106.901c-18.974-11.238-32.328-31.064-32.328-54.745 0-35.736 28.951-64.658 64.657-64.658 35.707 0 64.658 28.917 64.658 64.658 0 23.682-13.356 43.507-32.328 54.745z" + ], + "width": 1044, + "grid": 0, + "tags": [ + "lock39-open" + ] + }, + "properties": { + "order": 4, + "id": 66, + "prevSize": 32, + "code": 112, + "name": "lock39-open", + "ligatures": "" + }, + "setIdx": 0, + "iconIdx": 1 + }, + { + "icon": { + "paths": [ + "M102.030 101.608v819.555h819.555v-819.555h-819.555zM352.717 791.689h-165.288v-85.398h301.65v85.398zM792.109 360.562h-604.678v-128.099h603.303v128.099zM790.731 591.965h-603.303v-128.099h603.303v128.099z" + ], + "tags": [ + "form" + ], + "grid": 0 + }, "properties": { "order": 1, "id": 63, @@ -20,7 +64,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 0 + "iconIdx": 4 }, { "icon": { @@ -39,7 +83,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 1 + "iconIdx": 5 }, { "icon": { @@ -58,7 +102,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 2 + "iconIdx": 6 }, { "icon": { @@ -77,7 +121,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 3 + "iconIdx": 7 }, { "icon": { @@ -96,7 +140,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 4 + "iconIdx": 8 }, { "icon": { @@ -115,7 +159,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 5 + "iconIdx": 9 }, { "icon": { @@ -134,7 +178,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 6 + "iconIdx": 10 }, { "icon": { @@ -153,7 +197,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 7 + "iconIdx": 11 }, { "icon": { @@ -172,7 +216,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 8 + "iconIdx": 12 }, { "icon": { @@ -191,7 +235,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 9 + "iconIdx": 13 }, { "icon": { @@ -210,7 +254,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 10 + "iconIdx": 14 }, { "icon": { @@ -229,26 +273,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 11 - }, - { - "icon": { - "paths": [ - "M366 438h292v-108c0-42-14-76-42-104-30-28-64-44-104-44-40 0-74 16-104 44-28 28-42 62-42 104zM842 494v328c0 16-6 30-16 40-12 10-24 16-40 16h-548c-16 0-28-6-40-16-10-10-16-24-16-40v-328c0-16 6-28 16-40 12-10 24-16 40-16h18v-108c0-70 26-132 76-182s110-74 180-74c70 0 130 24 180 74 50 50 76 112 76 182v108h18c16 0 28 6 40 16 10 12 16 24 16 40z" - ], - "defaultCode": 109, - "grid": 0 - }, - "properties": { - "id": 11, - "order": 13, - "prevSize": 32, - "code": 109, - "name": "uni6D", - "ligatures": "" - }, - "setIdx": 0, - "iconIdx": 12 + "iconIdx": 15 }, { "icon": { @@ -267,7 +292,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 13 + "iconIdx": 17 }, { "icon": { @@ -286,7 +311,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 14 + "iconIdx": 18 }, { "icon": { @@ -305,26 +330,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 15 - }, - { - "icon": { - "paths": [ - "M988 330v146c0 10-4 18-12 26-6 6-16 10-26 10h-36c-10 0-18-4-26-10-6-8-10-16-10-26v-146c0-42-14-76-44-104-28-28-62-44-102-44-40 0-76 16-104 44-28 28-42 62-42 104v108h54c16 0 28 6 38 16 12 12 16 24 16 40v328c0 16-4 30-16 40-10 10-22 16-38 16h-548c-16 0-28-6-40-16-10-10-16-24-16-40v-328c0-16 6-28 16-40 12-10 24-16 40-16h384v-108c0-72 24-132 74-182s110-74 182-74c70 0 130 24 180 74 50 50 76 110 76 182z" - ], - "defaultCode": 112, - "grid": 0 - }, - "properties": { - "id": 15, - "order": 17, - "prevSize": 32, - "code": 112, - "name": "uni70", - "ligatures": "" - }, - "setIdx": 0, - "iconIdx": 16 + "iconIdx": 19 }, { "icon": { @@ -343,7 +349,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 17 + "iconIdx": 21 }, { "icon": { @@ -362,7 +368,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 18 + "iconIdx": 22 }, { "icon": { @@ -381,7 +387,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 19 + "iconIdx": 23 }, { "icon": { @@ -400,7 +406,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 20 + "iconIdx": 24 }, { "icon": { @@ -419,7 +425,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 21 + "iconIdx": 25 }, { "icon": { @@ -438,7 +444,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 22 + "iconIdx": 26 }, { "icon": { @@ -457,7 +463,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 23 + "iconIdx": 27 }, { "icon": { @@ -476,7 +482,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 24 + "iconIdx": 28 }, { "icon": { @@ -495,7 +501,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 25 + "iconIdx": 29 }, { "icon": { @@ -514,7 +520,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 26 + "iconIdx": 30 }, { "icon": { @@ -533,7 +539,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 27 + "iconIdx": 31 }, { "icon": { @@ -552,7 +558,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 28 + "iconIdx": 32 }, { "icon": { @@ -571,7 +577,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 29 + "iconIdx": 33 }, { "icon": { @@ -590,7 +596,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 30 + "iconIdx": 34 }, { "icon": { @@ -609,7 +615,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 31 + "iconIdx": 35 }, { "icon": { @@ -628,7 +634,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 32 + "iconIdx": 36 }, { "icon": { @@ -647,7 +653,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 33 + "iconIdx": 37 }, { "icon": { @@ -666,7 +672,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 34 + "iconIdx": 38 }, { "icon": { @@ -685,7 +691,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 35 + "iconIdx": 39 }, { "icon": { @@ -704,7 +710,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 36 + "iconIdx": 40 }, { "icon": { @@ -723,7 +729,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 37 + "iconIdx": 41 }, { "icon": { @@ -742,7 +748,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 38 + "iconIdx": 42 }, { "icon": { @@ -761,7 +767,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 39 + "iconIdx": 43 }, { "icon": { @@ -780,7 +786,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 40 + "iconIdx": 44 }, { "icon": { @@ -799,7 +805,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 41 + "iconIdx": 45 }, { "icon": { @@ -818,7 +824,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 42 + "iconIdx": 46 }, { "icon": { @@ -837,7 +843,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 43 + "iconIdx": 47 }, { "icon": { @@ -856,7 +862,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 44 + "iconIdx": 48 }, { "icon": { @@ -875,7 +881,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 45 + "iconIdx": 49 }, { "icon": { @@ -894,7 +900,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 46 + "iconIdx": 50 }, { "icon": { @@ -913,7 +919,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 47 + "iconIdx": 51 }, { "icon": { @@ -932,7 +938,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 48 + "iconIdx": 52 }, { "icon": { @@ -951,7 +957,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 49 + "iconIdx": 53 }, { "icon": { @@ -970,7 +976,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 50 + "iconIdx": 54 }, { "icon": { @@ -989,7 +995,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 51 + "iconIdx": 55 }, { "icon": { @@ -1008,7 +1014,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 52 + "iconIdx": 56 }, { "icon": { @@ -1027,7 +1033,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 53 + "iconIdx": 57 }, { "icon": { @@ -1046,7 +1052,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 54 + "iconIdx": 58 }, { "icon": { @@ -1065,7 +1071,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 55 + "iconIdx": 59 }, { "icon": { @@ -1084,7 +1090,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 56 + "iconIdx": 60 }, { "icon": { @@ -1103,7 +1109,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 57 + "iconIdx": 61 }, { "icon": { @@ -1122,7 +1128,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 58 + "iconIdx": 62 }, { "icon": { @@ -1141,7 +1147,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 59 + "iconIdx": 63 }, { "icon": { @@ -1160,7 +1166,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 60 + "iconIdx": 64 }, { "icon": { @@ -1179,7 +1185,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 61 + "iconIdx": 65 }, { "icon": { @@ -1198,7 +1204,7 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 62 + "iconIdx": 66 }, { "icon": { @@ -1217,12 +1223,12 @@ "ligatures": "" }, "setIdx": 0, - "iconIdx": 63 + "iconIdx": 67 } ], "height": 1024, "metadata": { - "name": "wagtail" + "name": "icomoon" }, "preferences": { "showGlyphs": true, @@ -1230,25 +1236,19 @@ "fontPref": { "prefix": "icon-", "metadata": { - "fontFamily": "wagtail", - "majorVersion": 1, - "minorVersion": 0 + "fontFamily": "icomoon" }, "metrics": { "emSize": 512, "baseline": 6.25, "whitespace": 50 - }, - "includeMetadata": false, - "showMetrics": false, - "showMetadata": false, - "showVersion": false, - "resetPoint": 33 + } }, "imagePref": {}, "historySize": 100, "showCodes": true, "search": "", - "gridSize": 16 + "gridSize": 16, + "showGrid": false } } \ No newline at end of file diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.eot b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.eot index 7d7860a83289d44e2dc32b0b001995f293d6a15c..bdadcd5ef1da44a7f28fd0af283427d32a52d5bd 100755 GIT binary patch delta 1016 zcmZ9LO=uHA6vy9tGqc-GwrR52#uk&b&DORyG2OIDqf~>3iiZjXK~O5#G>uj;iTFiD zAqpO(6r@DagW^f>D75HB^yEoV1o7ZS@F1R~7Ch_QXpp!&GrRBq-o7{U+nFb?@#Y&; z9VY=6*Hm6^K5_$V`|ZxtP=Xp%xYwY%R?Pe-JUmdp_4&sf0Nw+bKe|*dF2aM@D}drA z08B2iAimHTz`_XIgG-eQ%hzr5IopT$o8XyRspwn@du@dD+!@55}Gh7;U(<4`t}W6KfQ0!@s^soM^a?hOw6_hDM(^4)3Sa7I1X z3PI{k_J>hODT!pA_>vSFNH~_|BnCokG!G+=$aX+2nxr3pCSE$}lz6 zp=*?rN)ag~bEN4VYGsN9$MP^0jCOZ+c1MHjGlwHoCnnd2xA7^=!Bv1AX_0BR=5mMA zn4QcQa6Hn71(A10(ao@y(DVS>tObPL^LEYoCp#VU^;Z!Ln^p= zNId{LgAlB3A^!wqy|wmXGa8R^9ltq(Qt8sQ4s!lbYFEmNc(7ZnIWcn9WU3-6mpS*nv?_O4Kw4ROmg+BB(t}XoN@X|O@6N4PZ0#kJ zYgqtuQKrSit?`bDfQjpLAC^gI6v+&f)tYrp>mfZYWchFsPkh1?Gb;FE?_ zjskoO+ep79-I|*y%-;a>Jn0=;voAlD@uP#*dw`6f{KAAkKMno(n)Geb&6EB_HfgWE zAiYNQ$EK%d3&1G@qo2!p;JBV)-}*Zch9JgP*i&%fGC+NIZ%+c-6TBsAqq2F(3k55a zmV>41m%L(kR}*?oTzQpA&<(n3V~I;$YNloB%C=061m9-J5v7#;*EXjYl4RAGAq~ec zLT<#gy>NY<+OHI%l3Z~isZOSJ>LaDDajxl7nwG5(EOSi?OjY{`sqy7%>y#DoLWW@* zQqo|Ayoi;mZU?Y_bHK$Sg8-p!6Y3;cvda}`(F*TL_J_OO=7inI(r#B1Bhp4z;m4?I z)AkDcFx|(!bZ<{(vTI3*Ix|GZxxfH&P9TI#)@TGk);PrqljIF_YVp?)@gI|(?~;UV zGvX4PV@P)VY_&1%#h5_B&MC*Vghm!pNGVNNrlZodGjgU04OdVJSypjYUL)v$YhKu1-x}O74={k_&Y5dhoD<)n4$D6eyjlL(y7w+U9-)%b=EzqEV2JXo z{uAkcAnTrOPr! mpQjl*ApuFKshRV~3jTP$HV6Z>a15?Oo^IMqZLahzd;T}+Uy|AY diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg index dcfa5a08c60..96bbb662dcd 100755 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg @@ -3,7 +3,7 @@ Generated by IcoMoon - + @@ -57,10 +57,10 @@ - + - + diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.ttf b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.ttf index 38d2e1789c3dbff85017292ac2372a17f1b970bb..d2e09531318e38dd153af3e42274e525d46ddd4d 100755 GIT binary patch delta 984 zcmY+DO=uHA6vy9tGrQYOwrR3SV~a_eW^2EarkgftmD`Y-AoLD2K9{fVl8 z3dHaMZon86V1+{yK8m6pQtgaSSUwTOP>cp+VsIc&!`w$Po2IS=_oLXE&E(j!L^e-@ z12Jk2`ABmHi~XaR7P;Z(w6Hj%maB&#wI<_16jDkeStWiX1==zh} zCtKr+?$tD}u8>qEDXI|apJ~|>3vDJK<$NKs^tRINc-9U;N7JdF4w&5e!C5&!zr z(_yL-lWW8K_yQ*3Ccu%j$hghjZdV$!L&JF-2)AKg4BNeEXIM+9nh!&)`Gn?jX10g^ zvds$@t#uG!9h*ZIS9$wVX=>EE=)qu6?=rkz!yAo7jBds2(Iuj7Cex{a83>qR zha!;>h(a)A%L*{$grArI)1m7QQo+qZ>HyFfgkWtS`4Eux`rf;YNG!^Ayhb-lMU%F9 zg7XJbeJL~Sz^=3A#LQU;CjL*lkaNm7d0nK^slwGX>EK@9J^RvV<11;`@*S6&j{gKN zIoA~4ZIy4=zqQRm8+vLxg}o*ZRM`K_i6NfXcBUR4?(DwSWA}XM?daW2uBFt}T3;&t zs^8!L$xhYo6yHzHL6Hxu#JvJ#I0rMZ2um>MT5-rg8f>=yi|M%v-ng4Hhx7odIwtAu5 z-ShAp0DAy10mXth1;t+yz#|RWA|?1I>?Zw|bXRe%v~mZ`Vbc55b7XcQ@5RTg_W*f8 z^}BQ4$|8*5YtpNvJLbK)LfWprBK?HUpIuy7DgmboOnvq1!13veA0uUiaY(QY_8cN` z9iX|dKa;|q6z`1NsB9i~!!5O-^H{u=KhH9Qm>c8+tp70R>upE3oh!E%v_x7WYHN*4 zU23Lf>B_cDjRfCg$PuNK{Ldbz4M{SF<$BVPhGQ7vNX)d|XmgV~suZGwt zNJ?GfT+^jAEn6R5=b9AtIW$H{jjuOGXRVkUHVoU4k`^QE#;k1P2|fk}RTyHMU#{3# zW)LC>djw&g3U$Xx)^J>N-eYqD(#CR;-gZWg+gObZ##Of#K;!0uXu>p^Au`SdhLCge zL)HnAMm`9UQ?6N)yp>)bF!Ud+I;)p;M^W31MaZLLNH%b(F_`XROrT(wm19~$Ba)O- zN)wjps2tsloM}SC4OBwi_1>c_7oLWyeP z_lal8iR6cq6Q>}xmfAi2I1QE0`FE4c;K4MMXq|ysxC#Zh2}=|&(2whYGmwHb1kNmb a(LF4ed~l*@LOxVag7nf;&=*0E_D~ai>D;NI_wYOa`}>`bd(XM|mt+2s^0BtA zPTSO^1*p0V$v{`-SLtKrIWa%guY9sv?DP^<@>X#x!)bD5BhpQ#KJ75|@Q6NRYM89v{OxP63)%{{3YUu<>J;^h z;(H~#*R`ctrOxPI#qw2GC^oZqTUC$EEm+UtEf#$~A0j{I^?Aq1coaC?SFH*h_;77_iEB8nWwC@6ZTy?(L@K7i<(zzGg_Sln*jszD6SIP1h= zbO~-ZHEm(h!}B*h=s|uOgB)(LZczx~Q!b{6<*2ZMwTU*r4avrBl>dRn)up9XT*W0L zwsUE*AF&Q8Q=J)YEX-kCp}m}#SLOA)CUIgUV382}r>p@R_EWW8;5wJtzD3+zTv%A# z#Kk@?YG7vr;pxzf4{2KD9=>698#UOfYi-4vbshK8!3y&DWTV2d6-iUH&bXK4zNw z)oxpQ^&d!45ChnGYvzwmsk$PUNtSdKztfY!Lh*SyM?v?JPV=Rs2Mk~V6Tt#zXn`*1 m2Rrn{SsoNaA*hKR%Q^f_PKwY-h27wQKG0Kx69rPF^3FdqY%Zh# delta 814 zcmah{-%C?r7=Az9$y0_u3MGo@2PtGar-u8HXjF(aXkyw;P#tS*lAB{rr?xS2+u0d! z&aH2tqg{A0WO||C{(^3zF2bAcLJF_E?V^t0P477y#IE`{&-b18d7t;;f$uBMAI-G} z9mB(p@o@)$?Fh~QE!ze#-h8Ju(^(%G0q7rj?cM(5c--9!U>>0U3k~A+I@3#!D)BQHkttm!R0 zI&1ex3uI`Gk?53;2czJXJWk@?k;tmS)KL85o0+9S+h@{T)lo|wFc^R_CI%%}K$@E7 z2G({ldmIohQ_t6^?Q_kv!)e<3hxmQ=u%RNY9HkHJF1s{zYoqf`*R`%?W1!pI{na$t zbG~=4uetBw_F(Bx&0a@DwX3-nwH@)JfE%%VI2Xz-@gN3qDH;lg!?7it7u98J3!Yd6 zj4Cl%j>~Z+isH#83Q>%w;%PapyhkpgN(!FJq%-uTIEq=_bZ33LKx=Dl2X}BQQt%i2 z>(l5KaUzQXug8p%k<(;@(b6;HAd4I?tNSf@Pe3`DNF)?RPRb}Qq99{pC6Q8AldG5( z@tdADlnYnVE=DPAIW105GETl}ITK$YU$LA$8H>x5{y*8v-7w^9lp#m^$2i-Z=0Z>TBpi0QL*twTGdfJY*pW&s%;q0z9RDQPU94@x1lN zWDq29(G!$l3Z~%+IKdCI^gjb$dJ8>Z1QS$gDwkVL!Wa#@V2&&#GN>Bh2R8d(Qb!GH From b0d5b7cf956fd2222c97b78fafb3a52fcf632c60 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 12 Jun 2014 16:04:14 +0100 Subject: [PATCH 083/293] tweaking size of snippet icon --- .../wagtailadmin/scss/fonts/wagtail.eot | Bin 26120 -> 26124 bytes .../wagtailadmin/scss/fonts/wagtail.svg | 4 ++-- .../wagtailadmin/scss/fonts/wagtail.ttf | Bin 25956 -> 25960 bytes .../wagtailadmin/scss/fonts/wagtail.woff | Bin 15144 -> 15144 bytes 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.eot b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.eot index bdadcd5ef1da44a7f28fd0af283427d32a52d5bd..b1fad90917fdfbaae391544f6366b12bda0d53c4 100755 GIT binary patch delta 588 zcmeA;!`O3%k(DQnfgxiet2xVi+0ML)4kEne42cZs3?)D^lObnfq9K~VeAoJ~6}%M; z42&}v7!qPKQWH}c=Bc=JpW9AhV;$>xI;^5-+W#v|mOJ!2CwiDwLmXH(> zR#cSb*W=KQnUW`OZEhsaA)%-vBjfCBCn@V2pA=dfR1&NbQV}W>Iw7(`v_xf+ zr*cO1gqoB(k9wbmhDL>^k>)imHLVxgeL5UEeY$#j2lR#X?-=M!?n=3sgc6$!VGOAZ yMGVEjn9XO%0|urcFz^f*P}Gzsrk5mU=Aa5P1OYXsGn6vq0Fy-#s@&wgsonq@T#K0i delta 585 zcmeAjy$Vg30VVEm>lz}1f0|NttSq4ym`4N*o14EJqkgt-FTT;;|!m|g+_W|k= z$jMJmRIcWG$H0&r1C;N|O{^$j@Mk&)n zkm>@GXJBU9oXq${xW4B9Gsf?X4;UmF^cWb-^_a}e<(S3!n8o#&)nypv7{$f)80{Fv zMfe!i)a{tf`Iy<)$|ab{CmH+bNi&J-NC~hAh>7vCb8&Nrv+`GYT{` zs32G&q$E@#bWCKKXp`6xaTf6$i5ZeEQrD#Gq%X)Q$#y6zDOM=HQwmdBrW~VuN9C02 zF*ONwF7+M_HH|V&1I;U1Dq7F9dvw@zdUSR4_UQ}g-!jmd+?R4O2_+^O!WdE+iWrI+ vGC}bQ3`j#@z!?B}NU@!noS&PYpNA^Q5Cqhi&QQvb!;lCx07b*(gQ?yCy=;+8 diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg index 96bbb662dcd..4efa0249c4a 100755 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.svg @@ -3,7 +3,7 @@ Generated by IcoMoon - + @@ -22,7 +22,7 @@ - + diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.ttf b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail.ttf index d2e09531318e38dd153af3e42274e525d46ddd4d..0fef3a9104b626de878859f4acba311e1127ce0d 100755 GIT binary patch delta 538 zcmaEIit)uM#t9DfUn_Vk7#J95Ffb&uT^ ztjr*Sn*Y_~6Fy3N3$RNp}$G~8&$7E(M$1Kjr zEUw3_&L+nsF0RLD$0#nw$Ec=m$865W%)VVJR98A&*GWs9NmNyWkC|6gh?kX-iGz#N zmz7&NE|p2m+D?p1SVB@jSW!`yUynmKW=fvCwYiZvhlHYzjEu9housU9ke|GeptGYM zvtU%bIuo0qlDsT0mzbmsKLf*NebHk+@{9}&y@CQM@%%Pl8Mv81&Sp5jzwii*o-C5o z&e$_~PSVT7b6nea*m(Ext>K>}s3ce=q#{%%bV6i>Xp7h}aW?ThiCL0vQa7XN7mp&X}tPvwm22{kEo9`!yA4UGy-Bh71CYFaO}`*b*T`gHa54(JQ% z-!age{4DumQaM8+LpnnVkj!MrVF+VLWhi1O2D0-R@_=D!2n;*}1{5{riRmSYnK`I} X3_(DR=?tYnBNBlIplFyZnd%Jy^qhYr delta 534 zcmaEHit))Q#t9Df{r5jcGcYjDU|>jy$Vg30VVEm>lz}1f0|NttSq4ym`4N*o14EJq zkgt-FTT;;|!m|g+_W|k=$jMJmRIcWG$H0&r1C;N|O{^$j@Mk&)PGN1RSjN;;YjCPFTB7BT$>UPZLe9Y`?0iqKCl*y3Hkk60{#Q6+)3}FnZ3`GpZ44Gh_0)rti;0%B~BsH1I`MLS|d8mR6K|qb^ T45bV?42eJkP&7=IP4xxE}e+t|csuDUSoGE-tL|cqe z?6!osM5@F~DRZgkGUc-Vvg_n{Ut+*zFyAo1=)JL@iIhq8=5I`STyEYwMP26qj(zgI^82pu{1&?%C;J7I zB_~aA$i80qt>J8&?eyQW^DQ}UR*F{dO#iO;eQxul-)+A|rUcDdv~$(AP3xiy6Ef41 zH?QWsq&d09{GmJ}14CY??E83ro39MqObj4!et+Q+7(KbhqMfm4GmB+8V^TRoB11Yu z36RWW$YBU$NM$HuCu&;S$-lkZx2 F0{}cIj!FOk delta 413 zcmZ2cwxVo;=wu;lv5DF|oNWvYW^GR`MP^NO@MWGWdvxLib;dmtcc`$qNNl+_@qsLR zW^#URetzC$7DhY9+R4t0UVKmyn8a+xUx_=oSMtj73-JFExF=LCbXqt|__TcbiC0n Date: Thu, 12 Jun 2014 16:06:45 +0100 Subject: [PATCH 084/293] tweaking tabs --- .../wagtailadmin/static/wagtailadmin/scss/components/tabs.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss index cd805186288..2c85d24e82e 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss @@ -25,7 +25,7 @@ display:block; padding:0 20px; color:white; - border-top:0.3em solid $color-teal-darker; + border-top:0.3em solid lighten($color-teal-darker, 3%); border-bottom:1px solid transparent; &:hover{ From b038b6dbe7a1a91b2759af6b8c77598c0d41c60a Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 12 Jun 2014 16:14:15 +0100 Subject: [PATCH 085/293] fixing positioning of multiple panels relative to their controls --- .../static/wagtailadmin/scss/components/forms.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss index 3a6fc0d21ce..76a0879e3bb 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss @@ -297,7 +297,7 @@ button.icon{ > li{ position:relative; background-color:white; - padding:1em 1.5em; + padding:1em 10em 1em 1.5em; /* 10em padding leaves room for controls */ margin-bottom:1em; border:1px solid lighten($color-grey-4, 3%); /* really trying to avoid creating more greys, but this one is better than grey 4 or 5 */ @include border-radius(2px); @@ -319,6 +319,7 @@ button.icon{ /* Object controls */ .controls{ position:absolute; + z-index:1; right:1em; top:1em; color:white; From b4493af8b9ffa56efa9704f921cf20f716671665 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 12 Jun 2014 16:15:57 +0100 Subject: [PATCH 086/293] icomoon project file updated --- .../wagtailadmin/scss/fonts/wagtail-icomoon.json | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json index 12ad185e509..a7109db173a 100755 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/fonts/wagtail-icomoon.json @@ -544,7 +544,7 @@ { "icon": { "paths": [ - "M346 916c-160-46-618-248-98-916 280 190 388 358 408 496-134 48-226 142-214 312-74-174-132-416-156-566-12 176 14 488 60 674zM524 958c-38-106-118-456 482-438 18 550-274 530-404 492 54-106 124-202 212-282-108 60-206 136-290 228z" + "M365.797 867.819c-140.918-40.513-544.297-218.423-86.313-806.757 246.606 167.341 341.727 315.305 359.34 436.846-118.019 42.275-199.047 125.066-188.478 274.791-65.176-153.249-116.258-366.387-137.395-498.498-10.569 155.010 12.33 429.8 52.844 593.618zM522.569 904.81c-33.469-93.358-103.928-401.617 424.516-385.764 15.854 484.407-241.322 466.791-355.819 433.323 47.56-93.358 109.211-177.91 186.717-248.369-95.121 52.844-181.433 119.78-255.415 200.808z" ], "defaultCode": 68, "grid": 0 @@ -1228,7 +1228,7 @@ ], "height": 1024, "metadata": { - "name": "icomoon" + "name": "wagtail" }, "preferences": { "showGlyphs": true, @@ -1236,19 +1236,24 @@ "fontPref": { "prefix": "icon-", "metadata": { - "fontFamily": "icomoon" + "fontFamily": "wagtail", + "majorVersion": 1, + "minorVersion": 0 }, "metrics": { "emSize": 512, "baseline": 6.25, "whitespace": 50 - } + }, + "resetPoint": 58880, + "showMetrics": false, + "showMetadata": false }, "imagePref": {}, "historySize": 100, "showCodes": true, "search": "", "gridSize": 16, - "showGrid": false + "showGrid": true } } \ No newline at end of file From ff5879def9f465def8adc425f96d9dcdaf74a30b Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Fri, 13 Jun 2014 10:24:32 +0100 Subject: [PATCH 087/293] Add unit tests for wagtailcore/whitelist.py --- wagtail/wagtailcore/tests/test_whitelist.py | 136 ++++++++++++++++++++ wagtail/wagtailcore/whitelist.py | 5 +- 2 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 wagtail/wagtailcore/tests/test_whitelist.py diff --git a/wagtail/wagtailcore/tests/test_whitelist.py b/wagtail/wagtailcore/tests/test_whitelist.py new file mode 100644 index 00000000000..28b63d9fbe4 --- /dev/null +++ b/wagtail/wagtailcore/tests/test_whitelist.py @@ -0,0 +1,136 @@ +from bs4 import BeautifulSoup, NavigableString + +from django.test import TestCase +from wagtail.wagtailcore.whitelist import ( + check_url, + attribute_rule, + allow_without_attributes, + Whitelister +) + +class TestCheckUrl(TestCase): + def test_allowed_url_schemes(self): + for url_scheme in ['', 'http', 'https', 'ftp', 'mailto', 'tel']: + url = url_scheme + "://www.example.com" + self.assertTrue(bool(check_url(url))) + + def test_disallowed_url_scheme(self): + self.assertFalse(bool(check_url("invalid://url"))) + + +class TestAttributeRule(TestCase): + def setUp(self): + self.soup = BeautifulSoup('baz') + + def test_no_rule_for_attr(self): + """ + Test that attribute_rule() drops attributes for + which no rule has been defined. + """ + tag = self.soup.b + fn = attribute_rule({'snowman': 'barbecue'}) + fn(tag) + self.assertEqual(str(tag), 'baz') + + def test_rule_true_for_attr(self): + """ + Test that attribute_rule() does not change atrributes + when the corresponding rule returns True + """ + tag = self.soup.b + fn = attribute_rule({'foo': True}) + fn(tag) + self.assertEqual(str(tag), 'baz') + + def test_rule_false_for_attr(self): + """ + Test that attribute_rule() drops atrributes + when the corresponding rule returns False + """ + tag = self.soup.b + fn = attribute_rule({'foo': False}) + fn(tag) + self.assertEqual(str(tag), 'baz') + + def test_callable_called_on_attr(self): + """ + Test that when the rule returns a callable, + attribute_rule() replaces the attribute with + the result of calling the callable on the attribute. + """ + tag = self.soup.b + fn = attribute_rule({'foo': len}) + fn(tag) + self.assertEqual(str(tag), 'baz') + + def test_callable_returns_None(self): + """ + Test that when the rule returns a callable, + attribute_rule() replaces the attribute with + the result of calling the callable on the attribute. + """ + tag = self.soup.b + fn = attribute_rule({'foo': lambda x: None}) + fn(tag) + self.assertEqual(str(tag), 'baz') + + def test_allow_without_attributes(self): + """ + Test that attribute_rule() with will drop all + attributes. + """ + soup = BeautifulSoup('') + tag = soup.b + allow_without_attributes(tag) + self.assertEqual(str(tag), '') + + +class TestWhitelister(TestCase): + def test_clean_unknown_node(self): + """ + Unknown node should remove a node from the parent document + """ + soup = BeautifulSoup('bazquux') + tag = soup.foo + Whitelister.clean_unknown_node('', soup.bar) + self.assertEqual(str(tag), 'quux') + + def test_clean_tag_node_cleans_nested_recognised_node(self): + """ + tags are allowed without attributes. This remains true + when tags are nested. + """ + soup = BeautifulSoup('foo') + tag = soup.b + Whitelister.clean_tag_node(tag, tag) + self.assertEqual(str(tag), 'foo') + + def test_clean_tag_node_disallows_nested_unrecognised_node(self): + """ + tags should be removed, even when nested. + """ + soup = BeautifulSoup('bar') + tag = soup.b + Whitelister.clean_tag_node(tag, tag) + self.assertEqual(str(tag), 'bar') + + def test_clean_string_node_does_nothing(self): + soup = BeautifulSoup('bar') + string = soup.b.string + Whitelister.clean_string_node(string, string) + self.assertEqual(str(string), 'bar') + + def test_clean_node_does_not_change_navigable_strings(self): + soup = BeautifulSoup('bar') + string = soup.b.string + Whitelister.clean_node(string, string) + self.assertEqual(str(string), 'bar') + + def test_clean(self): + """ + Whitelister.clean should remove disallowed tags and attributes from + a string + """ + string = 'snowman Yorkshire' + cleaned_string = Whitelister.clean(string) + self.assertEqual(cleaned_string, 'snowman Yorkshire') diff --git a/wagtail/wagtailcore/whitelist.py b/wagtail/wagtailcore/whitelist.py index 508682cda21..a3d377bd630 100644 --- a/wagtail/wagtailcore/whitelist.py +++ b/wagtail/wagtailcore/whitelist.py @@ -89,7 +89,10 @@ def clean_node(cls, doc, node): cls.clean_string_node(doc, node) elif isinstance(node, Tag): cls.clean_tag_node(doc, node) - else: + # This branch is here in case node is a BeautifulSoup object that does + # not inherit from NavigableString or Tag. I can't find any examples + # of such a thing at the moment, so this branch is untested. + else: # pragma: no cover cls.clean_unknown_node(doc, node) @classmethod From cbd47f39419e9661a32d02c94acba17b398c890f Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 13 Jun 2014 13:33:01 +0100 Subject: [PATCH 088/293] Aesthetic improvements to preview experience. Loading spinner now uses wagtail's standard glyph. --- .../static/wagtailadmin/js/page-editor.js | 16 ++- .../pages/_preview_button_on_create.html | 2 +- .../pages/_preview_button_on_edit.html | 2 +- .../templates/wagtailadmin/pages/preview.html | 99 +++++++++++++++++++ .../pages/preview_placeholder.html | 18 ---- wagtail/wagtailadmin/urls.py | 3 +- wagtail/wagtailadmin/views/pages.py | 9 +- 7 files changed, 122 insertions(+), 27 deletions(-) create mode 100644 wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html delete mode 100644 wagtail/wagtailadmin/templates/wagtailadmin/pages/preview_placeholder.html diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js index 4e8e1b02dca..c98ea4c7fb8 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js +++ b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js @@ -334,16 +334,24 @@ $(function() { /* Set up behaviour of preview button */ $('.action-preview').click(function() { var previewWindow = window.open($(this).data('placeholder'), $(this).data('windowname')); - + $.ajax({ type: "POST", url: $(this).data('action'), data: $('#page-edit-form').serialize(), success: function(data, textStatus, request) { if (request.getResponseHeader('X-Wagtail-Preview') == 'ok') { - previewWindow.document.open(); - previewWindow.document.write(data); - previewWindow.document.close(); + var pdoc = previewWindow.document; + var frame = pdoc.getElementById('preview-frame'); + + frame = (frame.contentWindow) ? frame.contentWindow : (frame.contentDocument.document) ? frame.contentDocument.document : frame.contentDocument; + frame.document.open(); + frame.document.write(data); + frame.document.close(); + + var removeTimeout = setTimeout(function(){ + pdoc.getElementById('loading-spinner-wrapper').className += 'remove'; + }, 100) /* just enough to give effect without adding discernible slowness */ } else { previewWindow.close(); document.open(); diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/_preview_button_on_create.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/_preview_button_on_create.html index 7d71ed68b5a..4f60050be3c 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/_preview_button_on_create.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/_preview_button_on_create.html @@ -1,4 +1,4 @@ diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/_preview_button_on_edit.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/_preview_button_on_edit.html index b3478c94858..a5cd5d24aa3 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/_preview_button_on_edit.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/_preview_button_on_edit.html @@ -1,4 +1,4 @@ diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html new file mode 100644 index 00000000000..51b31acaaae --- /dev/null +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html @@ -0,0 +1,99 @@ + +{% load static %} + + + Preview loading... + + + + +
    +
    +
    + + + diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview_placeholder.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview_placeholder.html deleted file mode 100644 index 1ccfe1ffb9c..00000000000 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview_placeholder.html +++ /dev/null @@ -1,18 +0,0 @@ - -{% load static %} - - - Preview loading... - - - - - diff --git a/wagtail/wagtailadmin/urls.py b/wagtail/wagtailadmin/urls.py index 8fbf2f6e770..08620a45727 100644 --- a/wagtail/wagtailadmin/urls.py +++ b/wagtail/wagtailadmin/urls.py @@ -56,7 +56,8 @@ url(r'^pages/(\d+)/edit/$', pages.edit, name='wagtailadmin_pages_edit'), url(r'^pages/(\d+)/edit/preview/$', pages.preview_on_edit, name='wagtailadmin_pages_preview_on_edit'), - url(r'^pages/preview_placeholder/$', pages.preview_placeholder, name='wagtailadmin_pages_preview_placeholder'), + url(r'^pages/preview/$', pages.preview, name='wagtailadmin_pages_preview'), + url(r'^pages/preview_loading/$', pages.preview_loading, name='wagtailadmin_pages_preview_loading'), url(r'^pages/(\d+)/view_draft/$', pages.view_draft, name='wagtailadmin_pages_view_draft'), url(r'^pages/(\d+)/add_subpage/$', pages.add_subpage, name='wagtailadmin_pages_add_subpage'), diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py index 69e6b7f4f43..b5e87d1c250 100644 --- a/wagtail/wagtailadmin/views/pages.py +++ b/wagtail/wagtailadmin/views/pages.py @@ -395,7 +395,7 @@ def preview_on_create(request, content_type_app_name, content_type_model_name, p return response -def preview_placeholder(request): +def preview(request): """ The HTML of a previewed page is written to the destination browser window using document.write. This overwrites any previous content in the window, while keeping its URL intact. This in turn @@ -416,8 +416,13 @@ def preview_placeholder(request): Since we're going to this trouble, we'll also take the opportunity to display a spinner on the placeholder page, providing some much-needed visual feedback. """ - return render(request, 'wagtailadmin/pages/preview_placeholder.html') + return render(request, 'wagtailadmin/pages/preview.html') +def preview_loading(request): + """ + This page is blank, but must be real HTML so it's DOM can be written to once the preview of the page has rendered + """ + return HttpResponse("") @permission_required('wagtailadmin.access_admin') def unpublish(request, page_id): From cc2d8b68730dc90d8241f3b83f7a076dbadada91 Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Fri, 13 Jun 2014 14:18:16 +0100 Subject: [PATCH 089/293] Truncate long search strings Search query strings must not exceed 255 characters; they will be truncated if they do. Also added embedly library for Travis. --- .travis.yml | 2 +- wagtail/wagtailsearch/models.py | 6 +++++- wagtail/wagtailsearch/tests/test_queries.py | 10 ++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e23794d4f37..3e0a4bb986c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ services: # Package installation install: - python setup.py install - - pip install psycopg2 pyelasticsearch elasticutils==0.8.2 wand + - pip install psycopg2 pyelasticsearch elasticutils==0.8.2 wand embedly - pip install coveralls # Pre-test configuration before_script: diff --git a/wagtail/wagtailsearch/models.py b/wagtail/wagtailsearch/models.py index 809e139ed87..6b07872f53f 100644 --- a/wagtail/wagtailsearch/models.py +++ b/wagtail/wagtailsearch/models.py @@ -5,9 +5,10 @@ import datetime import string +MAX_QUERY_STRING_LENGTH = 255 class Query(models.Model): - query_string = models.CharField(max_length=255, unique=True) + query_string = models.CharField(max_length=MAX_QUERY_STRING_LENGTH, unique=True) def save(self, *args, **kwargs): # Normalise query string @@ -48,6 +49,9 @@ def get_most_popular(cls, date_since=None): @staticmethod def normalise_query_string(query_string): + # Truncate query string + if len(query_string) > MAX_QUERY_STRING_LENGTH: + query_string = query_string[:MAX_QUERY_STRING_LENGTH] # Convert query_string to lowercase query_string = query_string.lower() diff --git a/wagtail/wagtailsearch/tests/test_queries.py b/wagtail/wagtailsearch/tests/test_queries.py index 7086d46f434..7c65af6bf30 100644 --- a/wagtail/wagtailsearch/tests/test_queries.py +++ b/wagtail/wagtailsearch/tests/test_queries.py @@ -53,6 +53,16 @@ def test_different_queries(self): for query in queries: self.assertNotEqual(self.query, models.Query.get(query)) + def test_truncation(self): + test_querystring = 'a' * 1000 + result = models.Query.normalise_query_string(test_querystring) + self.assertEqual(len(result), 255) + + def test_no_truncation(self): + test_querystring = 'a' * 10 + result = models.Query.normalise_query_string(test_querystring) + self.assertEqual(len(result), 10) + class TestQueryPopularity(TestCase): def test_query_popularity(self): From 438ce4aba5c85fc36a821ce0677035407f5b0ecb Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 13 Jun 2014 15:40:06 +0100 Subject: [PATCH 090/293] improvements from kaedroho feedback --- wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js index c98ea4c7fb8..b8de0d13176 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js +++ b/wagtail/wagtailadmin/static/wagtailadmin/js/page-editor.js @@ -334,7 +334,7 @@ $(function() { /* Set up behaviour of preview button */ $('.action-preview').click(function() { var previewWindow = window.open($(this).data('placeholder'), $(this).data('windowname')); - + $.ajax({ type: "POST", url: $(this).data('action'), @@ -343,8 +343,8 @@ $(function() { if (request.getResponseHeader('X-Wagtail-Preview') == 'ok') { var pdoc = previewWindow.document; var frame = pdoc.getElementById('preview-frame'); - - frame = (frame.contentWindow) ? frame.contentWindow : (frame.contentDocument.document) ? frame.contentDocument.document : frame.contentDocument; + + frame = frame.contentWindow || frame.contentDocument.document || frame.contentDocument; frame.document.open(); frame.document.write(data); frame.document.close(); From 72a43567d25131c142795eae8bb4c51836215379 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 13 Jun 2014 16:15:37 +0100 Subject: [PATCH 091/293] tweaked transition --- .../templates/wagtailadmin/pages/preview.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html index 51b31acaaae..ead401777e0 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html @@ -30,13 +30,13 @@ font-size:0em; z-index:999999; background:white; - -webkit-transition: bottom 0.4s ease; - -moz-transition: bottom 0.4s ease; - -o-transition: bottom 0.4s ease; - transition: bottom 0.4s ease; + -webkit-transition: all 0.3s ease; + -moz-transition: all 0.3s ease; + -o-transition: all 0.3s ease; + transition: all 0.3s ease; } #loading-spinner-wrapper.remove{ - bottom:-100%; + bottom:-100%; } #loading-spinner-wrapper:before { content: ''; From d6aa265666c4670bf0126a234e743d6ae95eb5f2 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 13 Jun 2014 17:08:56 +0100 Subject: [PATCH 092/293] all fields now display required asterisk when necessary --- .../static/wagtailadmin/scss/components/forms.scss | 7 +++++++ .../templates/wagtailadmin/shared/field_as_li.html | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss index 29c44b4f3b8..8a0d4f97760 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss @@ -648,6 +648,13 @@ ul.tagit li.tagit-choice-editable{ } } +/* search-bars */ +.search-bar{ + .required label:after{ + display:none; + } +} + /* Transitions */ fieldset, input, textarea, select{ @include transition(background-color 0.2s ease); diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/shared/field_as_li.html b/wagtail/wagtailadmin/templates/wagtailadmin/shared/field_as_li.html index 678dd67fdfc..a1f51174a9a 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/shared/field_as_li.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/shared/field_as_li.html @@ -1,5 +1,5 @@ {% load wagtailadmin_tags %} -
  • +
  • {{ field.label_tag }}
    From dae521aec818054c850564b5d6dbe61c7b59714c Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Fri, 13 Jun 2014 17:21:51 +0100 Subject: [PATCH 093/293] removed redundant script block --- wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html b/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html index ead401777e0..3cacb7d1042 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/pages/preview.html @@ -3,9 +3,6 @@ Preview loading... - + {% trans "Preview" %} + {% compress css %} + + {% endcompress %} - +
    From 46fc45877cf479f57bd105afa485133108bc24a2 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 11:27:34 +0100 Subject: [PATCH 129/293] Replaced get_query_set methods with get_queryset --- wagtail/wagtailcore/models.py | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index b14181faf79..1f0c98d83e2 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -126,56 +126,56 @@ def get_navigable_page_content_type_ids(): class PageManager(models.Manager): - def get_query_set(self): + def get_queryset(self): return PageQuerySet(self.model).order_by('path') def live(self): - return self.get_query_set().live() + return self.get_queryset().live() def not_live(self): - return self.get_query_set().not_live() + return self.get_queryset().not_live() def page(self, other): - return self.get_query_set().page(other) + return self.get_queryset().page(other) def not_page(self, other): - return self.get_query_set().not_page(other) + return self.get_queryset().not_page(other) def descendant_of(self, other, inclusive=False): - return self.get_query_set().descendant_of(other, inclusive) + return self.get_queryset().descendant_of(other, inclusive) def not_descendant_of(self, other, inclusive=False): - return self.get_query_set().not_descendant_of(other, inclusive) + return self.get_queryset().not_descendant_of(other, inclusive) def child_of(self, other): - return self.get_query_set().child_of(other) + return self.get_queryset().child_of(other) def not_child_of(self, other): - return self.get_query_set().not_child_of(other) + return self.get_queryset().not_child_of(other) def ancestor_of(self, other, inclusive=False): - return self.get_query_set().ancestor_of(other, inclusive) + return self.get_queryset().ancestor_of(other, inclusive) def not_ancestor_of(self, other, inclusive=False): - return self.get_query_set().not_ancestor_of(other, inclusive) + return self.get_queryset().not_ancestor_of(other, inclusive) def parent_of(self, other): - return self.get_query_set().parent_of(other) + return self.get_queryset().parent_of(other) def not_parent_of(self, other): - return self.get_query_set().not_parent_of(other) + return self.get_queryset().not_parent_of(other) def sibling_of(self, other, inclusive=False): - return self.get_query_set().sibling_of(other, inclusive) + return self.get_queryset().sibling_of(other, inclusive) def not_sibling_of(self, other, inclusive=False): - return self.get_query_set().not_sibling_of(other, inclusive) + return self.get_queryset().not_sibling_of(other, inclusive) def type(self, model): - return self.get_query_set().type(model) + return self.get_queryset().type(model) def not_type(self, model): - return self.get_query_set().not_type(model) + return self.get_queryset().not_type(model) class PageBase(models.base.ModelBase): @@ -697,8 +697,8 @@ class Meta: class SubmittedRevisionsManager(models.Manager): - def get_query_set(self): - return super(SubmittedRevisionsManager, self).get_query_set().filter(submitted_for_moderation=True) + def get_queryset(self): + return super(SubmittedRevisionsManager, self).get_queryset().filter(submitted_for_moderation=True) class PageRevision(models.Model): From 1ca6de4d463e7ed62bf72bc758c07b4522a13bce Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 11:54:12 +0100 Subject: [PATCH 130/293] Improvements to wagtaildocs pagination tests --- wagtail/wagtaildocs/tests.py | 86 ++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/wagtail/wagtaildocs/tests.py b/wagtail/wagtaildocs/tests.py index 3353ce39ed9..576a3116f49 100644 --- a/wagtail/wagtaildocs/tests.py +++ b/wagtail/wagtaildocs/tests.py @@ -56,11 +56,46 @@ def test_search(self): self.assertEqual(response.status_code, 200) self.assertEqual(response.context['query_string'], "Hello") + def make_docs(self): + for i in range(50): + document = models.Document(title="Test " + str(i)) + document.save() + def test_pagination(self): - pages = ['0', '1', '-1', '9999', 'Not a page'] - for page in pages: - response = self.get({'p': page}) - self.assertEqual(response.status_code, 200) + self.make_docs() + + response = self.client.get(reverse('wagtaildocs_index'), {'p': 2}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/documents/index.html') + + # Check that we got the correct page + self.assertEqual(response.context['documents'].number, 2) + + def test_pagination_invalid(self): + self.make_docs() + + response = self.client.get(reverse('wagtaildocs_index'), {'p': 'Hello World!'}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/documents/index.html') + + # Check that we got page one + self.assertEqual(response.context['documents'].number, 1) + + def test_pagination_out_of_range(self): + self.make_docs() + + response = self.client.get(reverse('wagtaildocs_index'), {'p': 99999}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/documents/index.html') + + # Check that we got the last page + self.assertEqual(response.context['documents'].number, response.context['documents'].paginator.num_pages) def test_ordering(self): orderings = ['title', '-created_at'] @@ -138,11 +173,46 @@ def test_search(self): self.assertEqual(response.status_code, 200) self.assertEqual(response.context['query_string'], "Hello") + def make_docs(self): + for i in range(50): + document = models.Document(title="Test " + str(i)) + document.save() + def test_pagination(self): - pages = ['0', '1', '-1', '9999', 'Not a page'] - for page in pages: - response = self.get({'p': page}) - self.assertEqual(response.status_code, 200) + self.make_docs() + + response = self.client.get(reverse('wagtaildocs_chooser'), {'p': 2}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/documents/list.html') + + # Check that we got the correct page + self.assertEqual(response.context['documents'].number, 2) + + def test_pagination_invalid(self): + self.make_docs() + + response = self.client.get(reverse('wagtaildocs_chooser'), {'p': 'Hello World!'}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/documents/list.html') + + # Check that we got page one + self.assertEqual(response.context['documents'].number, 1) + + def test_pagination_out_of_range(self): + self.make_docs() + + response = self.client.get(reverse('wagtaildocs_chooser'), {'p': 99999}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtaildocs/documents/list.html') + + # Check that we got the last page + self.assertEqual(response.context['documents'].number, response.context['documents'].paginator.num_pages) class TestDocumentChooserChosenView(TestCase, WagtailTestUtils): From bf84b7f64a0903200f82a5b2ff562d6c639289aa Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 11:57:37 +0100 Subject: [PATCH 131/293] Removed get method from wagtaildocs tests --- wagtail/wagtaildocs/tests.py | 41 +++++++++--------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/wagtail/wagtaildocs/tests.py b/wagtail/wagtaildocs/tests.py index 576a3116f49..a39796c1de7 100644 --- a/wagtail/wagtaildocs/tests.py +++ b/wagtail/wagtaildocs/tests.py @@ -43,16 +43,13 @@ class TestDocumentIndexView(TestCase, WagtailTestUtils): def setUp(self): self.login() - def get(self, params={}): - return self.client.get(reverse('wagtaildocs_index'), params) - def test_simple(self): - response = self.get() + response = self.client.get(reverse('wagtaildocs_index')) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtaildocs/documents/index.html') def test_search(self): - response = self.get({'q': "Hello"}) + response = self.client.get(reverse('wagtaildocs_index'), {'q': "Hello"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context['query_string'], "Hello") @@ -100,7 +97,7 @@ def test_pagination_out_of_range(self): def test_ordering(self): orderings = ['title', '-created_at'] for ordering in orderings: - response = self.get({'ordering': ordering}) + response = self.client.get(reverse('wagtaildocs_index'), {'ordering': ordering}) self.assertEqual(response.status_code, 200) @@ -108,11 +105,8 @@ class TestDocumentAddView(TestCase, WagtailTestUtils): def setUp(self): self.login() - def get(self, params={}): - return self.client.get(reverse('wagtaildocs_add_document'), params) - def test_simple(self): - response = self.get() + response = self.client.get(reverse('wagtaildocs_add_document')) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtaildocs/documents/add.html') @@ -126,11 +120,8 @@ def setUp(self): # Create a document to edit self.document = models.Document.objects.create(title="Test document") - def get(self, params={}): - return self.client.get(reverse('wagtaildocs_edit_document', args=(self.document.id,)), params) - def test_simple(self): - response = self.get() + response = self.client.get(reverse('wagtaildocs_edit_document', args=(self.document.id,))) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtaildocs/documents/edit.html') @@ -144,11 +135,8 @@ def setUp(self): # Create a document to delete self.document = models.Document.objects.create(title="Test document") - def get(self, params={}): - return self.client.get(reverse('wagtaildocs_delete_document', args=(self.document.id,)), params) - def test_simple(self): - response = self.get() + response = self.client.get(reverse('wagtaildocs_delete_document', args=(self.document.id,))) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtaildocs/documents/confirm_delete.html') @@ -159,17 +147,14 @@ class TestDocumentChooserView(TestCase, WagtailTestUtils): def setUp(self): self.login() - def get(self, params={}): - return self.client.get(reverse('wagtaildocs_chooser'), params) - def test_simple(self): - response = self.get() + response = self.client.get(reverse('wagtaildocs_chooser')) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtaildocs/chooser/chooser.html') self.assertTemplateUsed(response, 'wagtaildocs/chooser/chooser.js') def test_search(self): - response = self.get({'q': "Hello"}) + response = self.client.get(reverse('wagtaildocs_chooser'), {'q': "Hello"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context['query_string'], "Hello") @@ -222,11 +207,8 @@ def setUp(self): # Create a document to choose self.document = models.Document.objects.create(title="Test document") - def get(self, params={}): - return self.client.get(reverse('wagtaildocs_document_chosen', args=(self.document.id,)), params) - def test_simple(self): - response = self.get() + response = self.client.get(reverse('wagtaildocs_document_chosen', args=(self.document.id,))) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtaildocs/chooser/document_chosen.js') @@ -237,11 +219,8 @@ class TestDocumentChooserUploadView(TestCase, WagtailTestUtils): def setUp(self): self.login() - def get(self, params={}): - return self.client.get(reverse('wagtaildocs_chooser_upload'), params) - def test_simple(self): - response = self.get() + response = self.client.get(reverse('wagtaildocs_chooser_upload')) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtaildocs/chooser/chooser.html') self.assertTemplateUsed(response, 'wagtaildocs/chooser/chooser.js') From 929aa0f5e8725f7bd678dcb6a15b87de481a3e05 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 12:26:15 +0100 Subject: [PATCH 132/293] Added posting tests to wagtaildocs --- wagtail/wagtaildocs/tests.py | 76 ++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 7 deletions(-) diff --git a/wagtail/wagtaildocs/tests.py b/wagtail/wagtaildocs/tests.py index a39796c1de7..a8420406baf 100644 --- a/wagtail/wagtaildocs/tests.py +++ b/wagtail/wagtaildocs/tests.py @@ -110,22 +110,58 @@ def test_simple(self): self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtaildocs/documents/add.html') - # TODO: Test posting + def test_post(self): + # Build a fake file + fake_file = ContentFile("A boring example document") + fake_file.name = 'test.txt' + + # Submit + post_data = { + 'title': "Test document", + 'file': fake_file, + } + response = self.client.post(reverse('wagtaildocs_add_document'), post_data) + + # User should be redirected back to the index + self.assertRedirects(response, reverse('wagtaildocs_index')) + + # Document should be created + self.assertTrue(models.Document.objects.filter(title="Test document").exists()) class TestDocumentEditView(TestCase, WagtailTestUtils): def setUp(self): self.login() + # Build a fake file + fake_file = ContentFile("A boring example document") + fake_file.name = 'test.txt' + # Create a document to edit - self.document = models.Document.objects.create(title="Test document") + self.document = models.Document.objects.create(title="Test document", file=fake_file) def test_simple(self): response = self.client.get(reverse('wagtaildocs_edit_document', args=(self.document.id,))) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtaildocs/documents/edit.html') - # TODO: Test posting + def test_post(self): + # Build a fake file + fake_file = ContentFile("A boring example document") + fake_file.name = 'test.txt' + + # Submit title change + post_data = { + 'title': "Test document changed!", + 'file': fake_file, + } + response = self.client.post(reverse('wagtaildocs_edit_document', args=(self.document.id,)), post_data) + + # User should be redirected back to the index + self.assertRedirects(response, reverse('wagtaildocs_index')) + + # Document title should be changed + self.assertEqual(models.Document.objects.get(id=self.document.id).title, "Test document changed!") class TestDocumentDeleteView(TestCase, WagtailTestUtils): @@ -140,7 +176,18 @@ def test_simple(self): self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtaildocs/documents/confirm_delete.html') - # TODO: Test posting + def test_delete(self): + # Submit title change + post_data = { + 'foo': 'bar' + } + response = self.client.post(reverse('wagtaildocs_delete_document', args=(self.document.id,)), post_data) + + # User should be redirected back to the index + self.assertRedirects(response, reverse('wagtaildocs_index')) + + # Document should be deleted + self.assertFalse(models.Document.objects.filter(id=self.document.id).exists()) class TestDocumentChooserView(TestCase, WagtailTestUtils): @@ -212,8 +259,6 @@ def test_simple(self): self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtaildocs/chooser/document_chosen.js') - # TODO: Test posting - class TestDocumentChooserUploadView(TestCase, WagtailTestUtils): def setUp(self): @@ -225,7 +270,24 @@ def test_simple(self): self.assertTemplateUsed(response, 'wagtaildocs/chooser/chooser.html') self.assertTemplateUsed(response, 'wagtaildocs/chooser/chooser.js') - # TODO: Test document upload with chooser + def test_post(self): + # Build a fake file + fake_file = ContentFile("A boring example document") + fake_file.name = 'test.txt' + + # Submit + post_data = { + 'title': "Test document", + 'file': fake_file, + } + response = self.client.post(reverse('wagtaildocs_chooser_upload'), post_data) + + # Check that the response is a javascript file saying the document was chosen + self.assertTemplateUsed(response, 'wagtaildocs/chooser/document_chosen.js') + self.assertContains(response, "modal.respond('documentChosen'") + + # Document should be created + self.assertTrue(models.Document.objects.filter(title="Test document").exists()) class TestDocumentFilenameProperties(TestCase): From ec46d09772a5ecc99e8352f65f73f984e764a501 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 13:05:33 +0100 Subject: [PATCH 133/293] Improved editors picks pagination tests --- .../wagtailsearch/tests/test_editorspicks.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/wagtail/wagtailsearch/tests/test_editorspicks.py b/wagtail/wagtailsearch/tests/test_editorspicks.py index 7ee974fd0d3..ed37d9c62c6 100644 --- a/wagtail/wagtailsearch/tests/test_editorspicks.py +++ b/wagtail/wagtailsearch/tests/test_editorspicks.py @@ -1,4 +1,5 @@ from django.test import TestCase +from django.core.urlresolvers import reverse from wagtail.tests.utils import unittest, WagtailTestUtils from wagtail.wagtailsearch import models @@ -68,6 +69,51 @@ def test_pagination(self): response = self.get({'p': page}) self.assertEqual(response.status_code, 200) + def make_editors_picks(self): + for i in range(50): + models.EditorsPick.objects.create( + query=models.Query.get("query " + str(i)), + page_id=1, + sort_order=0, + description="First editors pick", + ) + + def test_pagination(self): + self.make_editors_picks() + + response = self.client.get(reverse('wagtailsearch_editorspicks_index'), {'p': 2}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/index.html') + + # Check that we got the correct page + self.assertEqual(response.context['queries'].number, 2) + + def test_pagination_invalid(self): + self.make_editors_picks() + + response = self.client.get(reverse('wagtailsearch_editorspicks_index'), {'p': 'Hello World!'}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/index.html') + + # Check that we got page one + self.assertEqual(response.context['queries'].number, 1) + + def test_pagination_out_of_range(self): + self.make_editors_picks() + + response = self.client.get(reverse('wagtailsearch_editorspicks_index'), {'p': 99999}) + + # Check response + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/index.html') + + # Check that we got the last page + self.assertEqual(response.context['queries'].number, response.context['queries'].paginator.num_pages) + class TestEditorsPicksAddView(TestCase, WagtailTestUtils): def setUp(self): From 620e58632f374c464828f7e75a38b66b81517c6a Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 13:08:54 +0100 Subject: [PATCH 134/293] General improvements to editorspicks tests --- .../wagtailsearch/tests/test_editorspicks.py | 29 ++++--------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/wagtail/wagtailsearch/tests/test_editorspicks.py b/wagtail/wagtailsearch/tests/test_editorspicks.py index ed37d9c62c6..c92dd4ef632 100644 --- a/wagtail/wagtailsearch/tests/test_editorspicks.py +++ b/wagtail/wagtailsearch/tests/test_editorspicks.py @@ -1,5 +1,6 @@ from django.test import TestCase from django.core.urlresolvers import reverse + from wagtail.tests.utils import unittest, WagtailTestUtils from wagtail.wagtailsearch import models @@ -50,25 +51,16 @@ class TestEditorsPicksIndexView(TestCase, WagtailTestUtils): def setUp(self): self.login() - def get(self, params={}): - return self.client.get('/admin/search/editorspicks/', params) - def test_simple(self): - response = self.get() + response = self.client.get(reverse('wagtailsearch_editorspicks_index')) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/index.html') def test_search(self): - response = self.get({'q': "Hello"}) + response = self.client.get(reverse('wagtailsearch_editorspicks_index'), {'q': "Hello"}) self.assertEqual(response.status_code, 200) self.assertEqual(response.context['query_string'], "Hello") - def test_pagination(self): - pages = ['0', '1', '-1', '9999', 'Not a page'] - for page in pages: - response = self.get({'p': page}) - self.assertEqual(response.status_code, 200) - def make_editors_picks(self): for i in range(50): models.EditorsPick.objects.create( @@ -119,11 +111,8 @@ class TestEditorsPicksAddView(TestCase, WagtailTestUtils): def setUp(self): self.login() - def get(self, params={}): - return self.client.get('/admin/search/editorspicks/add/', params) - def test_simple(self): - response = self.get() + response = self.client.get(reverse('wagtailsearch_editorspicks_add')) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/add.html') @@ -138,11 +127,8 @@ def setUp(self): self.query = models.Query.get("Hello") self.query.editors_picks.create(page_id=1, description="Root page") - def get(self, params={}): - return self.client.get('/admin/search/editorspicks/' + str(self.query.id) + '/', params) - def test_simple(self): - response = self.get() + response = self.client.get(reverse('wagtailsearch_editorspicks_edit', args=(self.query.id, ))) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/edit.html') @@ -157,11 +143,8 @@ def setUp(self): self.query = models.Query.get("Hello") self.query.editors_picks.create(page_id=1, description="Root page") - def get(self, params={}): - return self.client.get('/admin/search/editorspicks/' + str(self.query.id) + '/delete/', params) - def test_simple(self): - response = self.get() + response = self.client.get(reverse('wagtailsearch_editorspicks_delete', args=(self.query.id, ))) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/confirm_delete.html') From a05df1a534d1f6cfadd65c7fdbcaf2f799e12e70 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 13:39:12 +0100 Subject: [PATCH 135/293] Added posting tests to editors picks --- .../wagtailsearch/tests/test_editorspicks.py | 135 +++++++++++++++++- 1 file changed, 130 insertions(+), 5 deletions(-) diff --git a/wagtail/wagtailsearch/tests/test_editorspicks.py b/wagtail/wagtailsearch/tests/test_editorspicks.py index c92dd4ef632..211a54cc9cb 100644 --- a/wagtail/wagtailsearch/tests/test_editorspicks.py +++ b/wagtail/wagtailsearch/tests/test_editorspicks.py @@ -116,7 +116,39 @@ def test_simple(self): self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/add.html') - # TODO: Test posting + def test_post(self): + # Submit + post_data = { + 'query_string': "test", + 'editors_picks-TOTAL_FORMS': 1, + 'editors_picks-INITIAL_FORMS': 0, + 'editors_picks-MAX_NUM_FORMS': 1000, + 'editors_picks-0-DELETE': '', + 'editors_picks-0-ORDER': 0, + 'editors_picks-0-page': 1, + 'editors_picks-0-description': "Hello", + } + response = self.client.post(reverse('wagtailsearch_editorspicks_add'), post_data) + + # User should be redirected back to the index + self.assertRedirects(response, reverse('wagtailsearch_editorspicks_index')) + + # Check that the editors pick was created + self.assertTrue(models.Query.get('test').editors_picks.filter(page_id=1).exists()) + + def test_post_without_recommendations(self): + # Submit + post_data = { + 'query_string': "test", + 'editors_picks-TOTAL_FORMS': 0, + 'editors_picks-INITIAL_FORMS': 0, + 'editors_picks-MAX_NUM_FORMS': 1000, + } + response = self.client.post(reverse('wagtailsearch_editorspicks_add'), post_data) + + # User should be given an error + self.assertEqual(response.status_code, 200) + self.assertFormsetError(response, 'editors_pick_formset', None, None, "Please specify at least one recommendation for this search term.") class TestEditorsPicksEditView(TestCase, WagtailTestUtils): @@ -125,14 +157,92 @@ def setUp(self): # Create an editors pick to edit self.query = models.Query.get("Hello") - self.query.editors_picks.create(page_id=1, description="Root page") + self.editors_pick = self.query.editors_picks.create(page_id=1, description="Root page") + self.editors_pick_2 = self.query.editors_picks.create(page_id=2, description="Homepage") def test_simple(self): response = self.client.get(reverse('wagtailsearch_editorspicks_edit', args=(self.query.id, ))) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/edit.html') - # TODO: Test posting + def test_post(self): + # Submit + post_data = { + 'query_string': "Hello", + 'editors_picks-TOTAL_FORMS': 2, + 'editors_picks-INITIAL_FORMS': 2, + 'editors_picks-MAX_NUM_FORMS': 1000, + 'editors_picks-0-id': self.editors_pick.id, + 'editors_picks-0-DELETE': '', + 'editors_picks-0-ORDER': 0, + 'editors_picks-0-page': 1, + 'editors_picks-0-description': "Description has changed", # Change + 'editors_picks-1-id': self.editors_pick_2.id, + 'editors_picks-1-DELETE': '', + 'editors_picks-1-ORDER': 0, + 'editors_picks-1-page': 2, + 'editors_picks-1-description': "Homepage", + } + response = self.client.post(reverse('wagtailsearch_editorspicks_edit', args=(self.query.id, )), post_data) + + # User should be redirected back to the index + self.assertRedirects(response, reverse('wagtailsearch_editorspicks_index')) + + # Check that the editors pick description was edited + self.assertEqual(models.EditorsPick.objects.get(id=self.editors_pick.id).description, "Description has changed") + + def test_post_delete_recommendation(self): + # Submit + post_data = { + 'query_string': "Hello", + 'editors_picks-TOTAL_FORMS': 2, + 'editors_picks-INITIAL_FORMS': 2, + 'editors_picks-MAX_NUM_FORMS': 1000, + 'editors_picks-0-id': self.editors_pick.id, + 'editors_picks-0-DELETE': '', + 'editors_picks-0-ORDER': 0, + 'editors_picks-0-page': 1, + 'editors_picks-0-description': "Root page", + 'editors_picks-1-id': self.editors_pick_2.id, + 'editors_picks-1-DELETE': 1, + 'editors_picks-1-ORDER': 0, + 'editors_picks-1-page': 2, + 'editors_picks-1-description': "Homepage", + } + response = self.client.post(reverse('wagtailsearch_editorspicks_edit', args=(self.query.id, )), post_data) + + # User should be redirected back to the index + self.assertRedirects(response, reverse('wagtailsearch_editorspicks_index')) + + # Check that the recommendation was deleted + self.assertFalse(models.EditorsPick.objects.filter(id=self.editors_pick_2.id).exists()) + + # The other recommendation should still exist + self.assertTrue(models.EditorsPick.objects.filter(id=self.editors_pick.id).exists()) + + def test_post_without_recommendations(self): + # Submit + post_data = { + 'query_string': "Hello", + 'editors_picks-TOTAL_FORMS': 2, + 'editors_picks-INITIAL_FORMS': 2, + 'editors_picks-MAX_NUM_FORMS': 1000, + 'editors_picks-0-id': self.editors_pick.id, + 'editors_picks-0-DELETE': 1, + 'editors_picks-0-ORDER': 0, + 'editors_picks-0-page': 1, + 'editors_picks-0-description': "Description has changed", # Change + 'editors_picks-1-id': self.editors_pick_2.id, + 'editors_picks-1-DELETE': 1, + 'editors_picks-1-ORDER': 0, + 'editors_picks-1-page': 2, + 'editors_picks-1-description': "Homepage", + } + response = self.client.post(reverse('wagtailsearch_editorspicks_edit', args=(self.query.id, )), post_data) + + # User should be given an error + self.assertEqual(response.status_code, 200) + self.assertFormsetError(response, 'editors_pick_formset', None, None, "Please specify at least one recommendation for this search term.") class TestEditorsPicksDeleteView(TestCase, WagtailTestUtils): @@ -141,11 +251,26 @@ def setUp(self): # Create an editors pick to delete self.query = models.Query.get("Hello") - self.query.editors_picks.create(page_id=1, description="Root page") + self.editors_pick = self.query.editors_picks.create(page_id=1, description="Root page") + self.editors_pick_2 = self.query.editors_picks.create(page_id=2, description="Homepage") def test_simple(self): response = self.client.get(reverse('wagtailsearch_editorspicks_delete', args=(self.query.id, ))) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailsearch/editorspicks/confirm_delete.html') - # TODO: Test posting + def test_post(self): + # Submit + post_data = { + 'foo': 'bar', + } + response = self.client.post(reverse('wagtailsearch_editorspicks_delete', args=(self.query.id, )), post_data) + + # User should be redirected back to the index + self.assertRedirects(response, reverse('wagtailsearch_editorspicks_index')) + + # Check that both recommendations were deleted + self.assertFalse(models.EditorsPick.objects.filter(id=self.editors_pick_2.id).exists()) + + # The other recommendation should still exist + self.assertFalse(models.EditorsPick.objects.filter(id=self.editors_pick.id).exists()) From e220c77cc01727650959173e47981755d4540e25 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 14:20:42 +0100 Subject: [PATCH 136/293] Added test to test reordering of editors picks --- .../wagtailsearch/tests/test_editorspicks.py | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/wagtail/wagtailsearch/tests/test_editorspicks.py b/wagtail/wagtailsearch/tests/test_editorspicks.py index 211a54cc9cb..99debab404b 100644 --- a/wagtail/wagtailsearch/tests/test_editorspicks.py +++ b/wagtail/wagtailsearch/tests/test_editorspicks.py @@ -179,7 +179,7 @@ def test_post(self): 'editors_picks-0-description': "Description has changed", # Change 'editors_picks-1-id': self.editors_pick_2.id, 'editors_picks-1-DELETE': '', - 'editors_picks-1-ORDER': 0, + 'editors_picks-1-ORDER': 1, 'editors_picks-1-page': 2, 'editors_picks-1-description': "Homepage", } @@ -191,6 +191,37 @@ def test_post(self): # Check that the editors pick description was edited self.assertEqual(models.EditorsPick.objects.get(id=self.editors_pick.id).description, "Description has changed") + def test_post_reorder(self): + # Check order before reordering + self.assertEqual(models.Query.get("Hello").editors_picks.all()[0], self.editors_pick) + self.assertEqual(models.Query.get("Hello").editors_picks.all()[1], self.editors_pick_2) + + # Submit + post_data = { + 'query_string': "Hello", + 'editors_picks-TOTAL_FORMS': 2, + 'editors_picks-INITIAL_FORMS': 2, + 'editors_picks-MAX_NUM_FORMS': 1000, + 'editors_picks-0-id': self.editors_pick.id, + 'editors_picks-0-DELETE': '', + 'editors_picks-0-ORDER': 1, # Change + 'editors_picks-0-page': 1, + 'editors_picks-0-description': "Root page", + 'editors_picks-1-id': self.editors_pick_2.id, + 'editors_picks-1-DELETE': '', + 'editors_picks-1-ORDER': 0, # Change + 'editors_picks-1-page': 2, + 'editors_picks-1-description': "Homepage", + } + response = self.client.post(reverse('wagtailsearch_editorspicks_edit', args=(self.query.id, )), post_data) + + # User should be redirected back to the index + self.assertRedirects(response, reverse('wagtailsearch_editorspicks_index')) + + # Check that the recommendations were reordered + self.assertEqual(models.Query.get("Hello").editors_picks.all()[0], self.editors_pick_2) + self.assertEqual(models.Query.get("Hello").editors_picks.all()[1], self.editors_pick) + def test_post_delete_recommendation(self): # Submit post_data = { @@ -205,7 +236,7 @@ def test_post_delete_recommendation(self): 'editors_picks-0-description': "Root page", 'editors_picks-1-id': self.editors_pick_2.id, 'editors_picks-1-DELETE': 1, - 'editors_picks-1-ORDER': 0, + 'editors_picks-1-ORDER': 1, 'editors_picks-1-page': 2, 'editors_picks-1-description': "Homepage", } @@ -234,7 +265,7 @@ def test_post_without_recommendations(self): 'editors_picks-0-description': "Description has changed", # Change 'editors_picks-1-id': self.editors_pick_2.id, 'editors_picks-1-DELETE': 1, - 'editors_picks-1-ORDER': 0, + 'editors_picks-1-ORDER': 1, 'editors_picks-1-page': 2, 'editors_picks-1-description': "Homepage", } From cbc401befe360490c49add0dfc86454cb3bf0543 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 14:50:42 +0100 Subject: [PATCH 137/293] Deleted test to test query popularity over time (not implemented) --- wagtail/wagtailsearch/tests/test_queries.py | 39 --------------------- 1 file changed, 39 deletions(-) diff --git a/wagtail/wagtailsearch/tests/test_queries.py b/wagtail/wagtailsearch/tests/test_queries.py index 5c341d7d652..70854c785eb 100644 --- a/wagtail/wagtailsearch/tests/test_queries.py +++ b/wagtail/wagtailsearch/tests/test_queries.py @@ -102,45 +102,6 @@ def test_query_popularity(self): self.assertEqual(popular_queries[1], models.Query.get("popular query")) self.assertEqual(popular_queries[2], models.Query.get("little popular query")) - @unittest.expectedFailure # Time based popularity isn't implemented yet - def test_query_popularity_over_time(self): - today = timezone.now().date() - two_days_ago = today - datetime.timedelta(days=2) - a_week_ago = today - datetime.timedelta(days=7) - a_month_ago = today - datetime.timedelta(days=30) - - # Add 10 hits to a query that was very popular query a month ago - for i in range(10): - models.Query.get("old popular query").add_hit(date=a_month_ago) - - # Add 5 hits to a query that is was popular 2 days ago - for i in range(5): - models.Query.get("new popular query").add_hit(date=two_days_ago) - - # Get most popular queries - popular_queries = models.Query.get_most_popular() - - # Old popular query should be most popular - self.assertEqual(popular_queries.count(), 2) - self.assertEqual(popular_queries[0], models.Query.get("old popular query")) - self.assertEqual(popular_queries[1], models.Query.get("new popular query")) - - # Get most popular queries for past week - past_week_popular_queries = models.Query.get_most_popular(date_since=a_week_ago) - - # Only new popular query should be in this list - self.assertEqual(past_week_popular_queries.count(), 1) - self.assertEqual(past_week_popular_queries[0], models.Query.get("new popular query")) - - # Old popular query gets a couple more hits! - for i in range(2): - models.Query.get("old popular query").add_hit() - - # Old popular query should now be in the most popular queries - self.assertEqual(past_week_popular_queries.count(), 2) - self.assertEqual(past_week_popular_queries[0], models.Query.get("new popular query")) - self.assertEqual(past_week_popular_queries[1], models.Query.get("old popular query")) - class TestGarbageCollectCommand(TestCase): def test_garbage_collect_command(self): From 9c0f4212e339fc0aa1c8b94f05778f65be4dc536 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 15:49:02 +0100 Subject: [PATCH 138/293] Only allow logged in users to access the userbar views --- wagtail/wagtailadmin/views/userbar.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/views/userbar.py b/wagtail/wagtailadmin/views/userbar.py index 6e6ef349207..41776f6841b 100644 --- a/wagtail/wagtailadmin/views/userbar.py +++ b/wagtail/wagtailadmin/views/userbar.py @@ -1,9 +1,13 @@ from django.shortcuts import render +from django.contrib.auth.decorators import permission_required from wagtail.wagtailadmin.userbar import EditPageItem, AddPageItem, ApproveModerationEditPageItem, RejectModerationEditPageItem from wagtail.wagtailadmin import hooks from wagtail.wagtailcore.models import Page, PageRevision + + +@permission_required('wagtailadmin.access_admin') def for_frontend(request, page_id): items = [ EditPageItem(Page.objects.get(id=page_id)), @@ -24,6 +28,8 @@ def for_frontend(request, page_id): 'items': rendered_items, }) + +@permission_required('wagtailadmin.access_admin') def for_moderation(request, revision_id): items = [ EditPageItem(PageRevision.objects.get(id=revision_id).page), @@ -44,4 +50,4 @@ def for_moderation(request, revision_id): # Render the edit bird return render(request, 'wagtailadmin/userbar/base.html', { 'items': rendered_items, - }) \ No newline at end of file + }) From 3577e618806f79f2ebf83af96eeff75a5ab4c05e Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 15:58:22 +0100 Subject: [PATCH 139/293] Raise exception if userbar views are accessed by anonymous user --- wagtail/wagtailadmin/views/userbar.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/wagtail/wagtailadmin/views/userbar.py b/wagtail/wagtailadmin/views/userbar.py index 41776f6841b..2b3749da011 100644 --- a/wagtail/wagtailadmin/views/userbar.py +++ b/wagtail/wagtailadmin/views/userbar.py @@ -6,8 +6,7 @@ from wagtail.wagtailcore.models import Page, PageRevision - -@permission_required('wagtailadmin.access_admin') +@permission_required('wagtailadmin.access_admin', raise_exception=True) def for_frontend(request, page_id): items = [ EditPageItem(Page.objects.get(id=page_id)), @@ -29,7 +28,7 @@ def for_frontend(request, page_id): }) -@permission_required('wagtailadmin.access_admin') +@permission_required('wagtailadmin.access_admin', raise_exception=True) def for_moderation(request, revision_id): items = [ EditPageItem(PageRevision.objects.get(id=revision_id).page), From ed4af844dec210792e5e9dd474b7d7211769f3d2 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 15:58:54 +0100 Subject: [PATCH 140/293] Added tests for userbar --- wagtail/wagtailadmin/tests/test_userbar.py | 82 ++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 wagtail/wagtailadmin/tests/test_userbar.py diff --git a/wagtail/wagtailadmin/tests/test_userbar.py b/wagtail/wagtailadmin/tests/test_userbar.py new file mode 100644 index 00000000000..52ec2d60ad6 --- /dev/null +++ b/wagtail/wagtailadmin/tests/test_userbar.py @@ -0,0 +1,82 @@ +from django.test import TestCase +from django.test.client import RequestFactory +from django.core.urlresolvers import reverse +from django.template import Template, Context +from django.contrib.auth.models import User, AnonymousUser + +from wagtail.tests.utils import WagtailTestUtils +from wagtail.wagtailcore.models import Page + + +class TestUserbarTag(TestCase): + def setUp(self): + self.user = User.objects.create_superuser(username='test', email='test@email.com', password='password') + self.homepage = Page.objects.get(id=2) + + def dummy_request(self, user=None): + request = RequestFactory().get('/') + request.user = user or AnonymousUser() + return request + + def test_userbar_tag(self): + template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}") + content = template.render(Context({ + 'self': self.homepage, + 'request': self.dummy_request(self.user), + })) + + self.assertIn("", content) + + def test_userbar_tag_anonymous_user(self): + template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}") + content = template.render(Context({ + 'self': self.homepage, + 'request': self.dummy_request(), + })) + + # Make sure nothing was rendered + self.assertEqual(content, '') + + +class TestUserbarFrontend(TestCase, WagtailTestUtils): + def setUp(self): + self.login() + self.homepage = Page.objects.get(id=2) + + def test_userbar_frontend(self): + response = self.client.get(reverse('wagtailadmin_userbar_frontend', args=(self.homepage.id, ))) + + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailadmin/userbar/base.html') + + def test_userbar_anonymous_user_cannot_see(self): + # Logout + self.client.logout() + + response = self.client.get(reverse('wagtailadmin_userbar_frontend', args=(self.homepage.id, ))) + + # Check that the user recieved a forbidden message + self.assertEqual(response.status_code, 403) + + +class TestUserbarModeration(TestCase, WagtailTestUtils): + def setUp(self): + self.login() + self.homepage = Page.objects.get(id=2) + self.homepage.save_revision() + self.revision = self.homepage.get_latest_revision() + + def test_userbar_frontend(self): + response = self.client.get(reverse('wagtailadmin_userbar_moderation', args=(self.revision.id, ))) + + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'wagtailadmin/userbar/base.html') + + def test_userbar_anonymous_user_cannot_see(self): + # Logout + self.client.logout() + + response = self.client.get(reverse('wagtailadmin_userbar_moderation', args=(self.revision.id, ))) + + # Check that the user recieved a forbidden message + self.assertEqual(response.status_code, 403) From 733294cafa45a191478b4dccce4d7f5a22ee98de Mon Sep 17 00:00:00 2001 From: Robert Clark Date: Wed, 18 Jun 2014 11:04:39 -0400 Subject: [PATCH 141/293] return a queryset instead of the first sibling --- wagtail/wagtailcore/models.py | 8 ++++---- wagtail/wagtailcore/tests/test_page_queryset.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index e2b72800521..9dcc65f6f1d 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -645,11 +645,11 @@ def get_descendants(self, inclusive=False): def get_siblings(self, inclusive=True): return Page.objects.sibling_of(self, inclusive) - def get_next_published_sibling(self): - return self.get_siblings().live().filter(path__gt=self.path).order_by('path').first() + def get_next_siblings(self): + return self.get_siblings().filter(path__gt=self.path).order_by('path') - def get_prev_published_sibling(self): - return self.get_siblings().live().filter(path__lt=self.path).order_by('-path').first() + def get_prev_siblings(self): + return self.get_siblings().filter(path__lt=self.path).order_by('-path') def get_navigation_menu_items(): # Get all pages that appear in the navigation menu: ones which have children, diff --git a/wagtail/wagtailcore/tests/test_page_queryset.py b/wagtail/wagtailcore/tests/test_page_queryset.py index 3db3bd5f8fd..020d98d153a 100644 --- a/wagtail/wagtailcore/tests/test_page_queryset.py +++ b/wagtail/wagtailcore/tests/test_page_queryset.py @@ -262,7 +262,7 @@ def test_published_next(self): # All pages must be live while current_page: self.assertTrue(current_page.live) - current_page = current_page.get_next_published_sibling() + current_page = current_page.get_next_siblings().live().first() def test_published_prev(self): events_index = Page.objects.get(url_path='/home/events/') @@ -271,4 +271,4 @@ def test_published_prev(self): # All pages must be live while current_page: self.assertTrue(current_page.live) - current_page = current_page.get_prev_published_sibling() + current_page = current_page.get_prev_siblings().live().first() From 3778c476bb8b8f9972e0857d0c6bd0ea4ca2c235 Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Wed, 18 Jun 2014 17:16:04 +0100 Subject: [PATCH 142/293] Add unit tests for edit_handlers.py. Lint edit_handlers.py. --- .gitignore | 1 + wagtail/wagtailadmin/edit_handlers.py | 77 ++- .../wagtailadmin/tests/test_edit_handlers.py | 523 ++++++++++++++++++ 3 files changed, 572 insertions(+), 29 deletions(-) create mode 100644 wagtail/wagtailadmin/tests/test_edit_handlers.py diff --git a/.gitignore b/.gitignore index bd904efc9d6..57f9d0eab5e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.pyc .DS_Store +/.ropeproject/ /.coverage /dist/ /MANIFEST diff --git a/wagtail/wagtailadmin/edit_handlers.py b/wagtail/wagtailadmin/edit_handlers.py index 245f7ad60d1..39f38d499f6 100644 --- a/wagtail/wagtailadmin/edit_handlers.py +++ b/wagtail/wagtailadmin/edit_handlers.py @@ -12,7 +12,11 @@ from django.db import models from django.forms.models import fields_for_model from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured, ValidationError +from django.core.exceptions import ( + ObjectDoesNotExist, + ImproperlyConfigured, + ValidationError +) from django.core.urlresolvers import reverse from django.conf import settings from django.utils.translation import ugettext as _ @@ -33,7 +37,8 @@ def __init__(self, attrs=None): if attrs: default_attrs.update(attrs) - super(FriendlyDateInput, self).__init__(attrs=default_attrs, format='%d %b %Y') + super(FriendlyDateInput, self).__init__(attrs=default_attrs, + format='%d %b %Y') class FriendlyTimeInput(forms.TimeInput): @@ -46,7 +51,8 @@ def __init__(self, attrs=None): if attrs: default_attrs.update(attrs) - super(FriendlyTimeInput, self).__init__(attrs=default_attrs, format='%I.%M%p') + super(FriendlyTimeInput, self).__init__(attrs=default_attrs, + format='%I.%M%p') class FriendlyTimeField(forms.CharField): @@ -87,7 +93,7 @@ class LocalizedDateInput(forms.DateInput): and adds class="friendly_date" to be picked up by jquery datepicker. """ def __init__(self, attrs=None): - default_attrs = {'class': 'localized_date', 'localize':True} + default_attrs = {'class': 'localized_date', 'localize': True} if attrs: default_attrs.update(attrs) @@ -104,7 +110,8 @@ def __init__(self, attrs=None): if attrs: default_attrs.update(attrs) # Just use 24-hour format - super(LocalizedTimeInput, self).__init__(attrs=default_attrs, format='%H:%M') + super(LocalizedTimeInput, self).__init__(attrs=default_attrs, + format='%H:%M') class LocalizedTimeField(forms.CharField): @@ -118,7 +125,7 @@ def to_python(self, time_string): match = expr.match(time_string.lower()) if match: # Pull out values from string - hour_string, minute_string= match.groups() + hour_string, minute_string = match.groups() # Convert hours and minutes to integers hour = int(hour_string) @@ -126,31 +133,38 @@ def to_python(self, time_string): minute = int(minute_string) else: minute = 0 - if hour>=24 or hour < 0 or minute >=60 or minute < 0: + if hour >= 24 or hour < 0 or minute >= 60 or minute < 0: raise ValidationError(_("Please type a valid time")) return datetime.time(hour=hour, minute=minute) else: - raise ValidationError(_("Please type a valid time") ) + raise ValidationError(_("Please type a valid time")) -if hasattr(settings, 'USE_L10N') and settings.USE_L10N==True: +if hasattr(settings, 'USE_L10N') and settings.USE_L10N is True: FORM_FIELD_OVERRIDES = { models.DateField: {'widget': LocalizedDateInput}, - models.TimeField: {'widget': LocalizedTimeInput, 'form_class': LocalizedTimeField}, + models.TimeField: {'widget': LocalizedTimeInput, + 'form_class': LocalizedTimeField}, } -else: # Fall back to friendly date/time +else: # Fall back to friendly date/time FORM_FIELD_OVERRIDES = { models.DateField: {'widget': FriendlyDateInput}, - models.TimeField: {'widget': FriendlyTimeInput, 'form_class': FriendlyTimeField}, + models.TimeField: {'widget': FriendlyTimeInput, + 'form_class': FriendlyTimeField}, } WIDGET_JS = { - FriendlyDateInput: (lambda id: "initFriendlyDateChooser(fixPrefix('%s'));" % id), - FriendlyTimeInput: (lambda id: "initFriendlyTimeChooser(fixPrefix('%s'));" % id), - LocalizedDateInput: (lambda id: "initLocalizedDateChooser(fixPrefix('%s'));" % id), - LocalizedTimeInput: (lambda id: "initLocalizedTimeChooser(fixPrefix('%s'));" % id), - RichTextArea: (lambda id: "makeRichTextEditable(fixPrefix('%s'));" % id), + FriendlyDateInput: (lambda id: "initFriendlyDateChooser(fixPrefix('%s'));" + % id), + FriendlyTimeInput: (lambda id: "initFriendlyTimeChooser(fixPrefix('%s'));" + % id), + LocalizedDateInput: (lambda id: "initLocalizedDateChooser(fixPrefix('%s'));" + % id), + LocalizedTimeInput: (lambda id: "initLocalizedTimeChooser(fixPrefix('%s'));" + % id), + RichTextArea: (lambda id: "makeRichTextEditable(fixPrefix('%s'));" + % id), TagWidget: ( lambda id: "initTagField(fixPrefix('%s'), '%s');" % ( id, addslashes(reverse('wagtailadmin_tag_autocomplete')) @@ -159,7 +173,8 @@ def to_python(self, time_string): } -# Callback to allow us to override the default form fields provided for each model field. +# Callback to allow us to override the default form fields provided +# for each model field. def formfield_for_dbfield(db_field, **kwargs): # snarfed from django/contrib/admin/options.py @@ -177,13 +192,13 @@ def formfield_for_dbfield(db_field, **kwargs): class WagtailAdminModelFormMetaclass(ClusterFormMetaclass): # Override the behaviour of the regular ModelForm metaclass - # which handles the translation of model fields to form fields - - # to use our own formfield_for_dbfield function to do that translation. - # This is done by sneaking a formfield_callback property into the class - # being defined (unless the class already provides a formfield_callback - # of its own). + # to use our own formfield_for_dbfield function to do that + # translation. This is done by sneaking a formfield_callback + # property into the class being defined (unless the class already + # provides a formfield_callback of its own). - # while we're at it, we'll also set extra_form_count to 0, as we're creating - # extra forms in JS + # while we're at it, we'll also set extra_form_count to 0, as + # we're creating extra forms in JS extra_form_count = 0 def __new__(cls, name, bases, attrs): @@ -200,8 +215,8 @@ def __new__(cls, name, bases, attrs): def get_form_for_model( - model, - fields=None, exclude=None, formsets=None, exclude_formsets=None, widgets=None + model, fields=None, exclude=None, formsets=None, + exclude_formsets=None, widgets=None ): # django's modelform_factory with a bit of custom behaviour @@ -215,7 +230,8 @@ def get_form_for_model( if exclude is not None: attrs['exclude'] = exclude if issubclass(model, Page): - attrs['exclude'] = attrs.get('exclude', []) + ['content_type', 'path', 'depth', 'numchild'] + attrs['exclude'] = attrs.get('exclude', []) + ['content_type', 'path', + 'depth', 'numchild'] if widgets is not None: attrs['widgets'] = widgets @@ -232,7 +248,9 @@ def get_form_for_model( 'Meta': type('Meta', (object,), attrs) } - return WagtailAdminModelFormMetaclass(class_name, (WagtailAdminModelForm,), form_class_attrs) + return WagtailAdminModelFormMetaclass(class_name, + (WagtailAdminModelForm,), + form_class_attrs) def extract_panel_definitions_from_model_class(model, exclude=None): @@ -247,7 +265,8 @@ def extract_panel_definitions_from_model_class(model, exclude=None): if issubclass(model, Page): _exclude = ['content_type', 'path', 'depth', 'numchild'] - fields = fields_for_model(model, exclude=_exclude, formfield_callback=formfield_for_dbfield) + fields = fields_for_model(model, exclude=_exclude, + formfield_callback=formfield_for_dbfield) for field_name, field in fields.items(): try: diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py new file mode 100644 index 00000000000..45db35c5ba0 --- /dev/null +++ b/wagtail/wagtailadmin/tests/test_edit_handlers.py @@ -0,0 +1,523 @@ +from mock import MagicMock + +from django.test import TestCase +from django.core.exceptions import ValidationError + +from wagtail.wagtailadmin.edit_handlers import ( + FriendlyDateInput, + FriendlyTimeInput, + FriendlyTimeField, + LocalizedTimeInput, + LocalizedDateInput, + LocalizedTimeField, + get_form_for_model, + extract_panel_definitions_from_model_class, + BaseFieldPanel, + FieldPanel, + RichTextFieldPanel, + EditHandler, + WagtailAdminModelForm, + BaseCompositeEditHandler, + BaseTabbedInterface, + TabbedInterface, + BaseObjectList, + ObjectList, + PageChooserPanel +) +from wagtail.wagtailcore.models import Page, Site + + +class TestFriendlyDateInput(TestCase): + def test_attrs(self): + """ + When the attrs argument is passed to FriendlyDateInput's + constructor, they should be set on the FriendlyDateInput + object along with the default attrs + """ + friendly = FriendlyDateInput(attrs={'awesome': 'sauce'}) + self.assertEqual(friendly.attrs, {'class': 'friendly_date', + 'awesome': 'sauce'}) + + +class TestFriendlyTimeInput(TestCase): + def test_attrs(self): + """ + When the attrs argument is passed to FriendlyDateInput's + constructor, they should be set on the FriendlyDateInput + object along with the default attrs + """ + friendly = FriendlyTimeInput(attrs={'awesome': 'sauce'}) + self.assertEqual(friendly.attrs, {'class': 'friendly_time', + 'awesome': 'sauce'}) + + +class TestFriendlyTimeField(TestCase): + def setUp(self): + self.friendly = FriendlyTimeField() + + def test_no_time_string(self): + """ + to_python() should return None if it is passed an empty + string + """ + result = self.friendly.to_python('') + self.assertEqual(result, None) + + def test_invalid_time_string(self): + """ + to_python() should raise a ValidationError if it is passed + an invalid time string + """ + self.assertRaises(ValidationError, self.friendly.to_python, 'bacon') + + def test_afternoon_time_string(self): + """ + to_python() should convert a time string that ends with 'pm' + to a 24-hour time in the afternoon + """ + python_time = self.friendly.to_python('3:49pm') + self.assertEqual(str(python_time), '15:49:00') + + def test_morning_time_string(self): + """ + to_python() should convert a time string that ends with 'am' + to a 24-hour time in the morning + """ + python_time = self.friendly.to_python('3:49am') + self.assertEqual(str(python_time), '03:49:00') + + def test_no_minutes_time_string(self): + """ + If minutes are not specified in the time string, they should + default to zero + """ + python_time = self.friendly.to_python('3am') + self.assertEqual(str(python_time), '03:00:00') + + +class TestLocalizedDateInput(TestCase): + def test_attrs(self): + """ + When the attrs argument is passed to LocalizedDateInput's + constructor, they should be set on the LocalizedDateInput + object along with the default attrs + """ + localized = LocalizedDateInput(attrs={'awesome': 'sauce'}) + self.assertEqual(localized.attrs, {'class': 'localized_date', + 'localize': True, + 'awesome': 'sauce'}) + + +class TestLocalizedTimeInput(TestCase): + def test_attrs(self): + """ + When the attrs argument is passed to LocalizedTimeInput's + constructor, they should be set on the LocalizedTimeInput + object along with the default attrs + """ + localized = LocalizedTimeInput(attrs={'awesome': 'sauce'}) + self.assertEqual(localized.attrs, {'class': 'localized_time', + 'awesome': 'sauce'}) + + +class TestLocalizedTimeField(TestCase): + def setUp(self): + self.localized = LocalizedTimeField() + + def test_no_time_string(self): + """ + to_python() should return None if it is passed an empty + string + """ + result = self.localized.to_python('') + self.assertEqual(result, None) + + def test_non_time_string(self): + """ + to_python() should raise a ValidationError if it is passed + a string that does not represent a time + """ + self.assertRaises(ValidationError, self.localized.to_python, 'bacon') + + def test_invalid_time_string(self): + """ + to_python() should raise a ValidationError if it is passed + an invalid time string + """ + self.assertRaises(ValidationError, self.localized.to_python, '99:99') + + def test_afternoon_time_string(self): + """ + to_python() should understand 24-hour time + """ + python_time = self.localized.to_python('15:49') + self.assertEqual(str(python_time), '15:49:00') + + def test_morning_time_string(self): + """ + to_python() should understand 24-hour time + """ + python_time = self.localized.to_python('3:49') + self.assertEqual(str(python_time), '03:49:00') + + def test_no_minutes_time_string(self): + """ + If minutes are not specified in the time string, they should + default to zero + """ + python_time = self.localized.to_python('3') + self.assertEqual(str(python_time), '03:00:00') + + +class TestGetFormForModel(TestCase): + class FakeClass(object): + _meta = MagicMock() + + def setUp(self): + self.mock_exclude = MagicMock() + + def test_get_form_for_model(self): + form = get_form_for_model(self.FakeClass, + fields=[], + exclude=[self.mock_exclude], + formsets=['baz'], + exclude_formsets=['quux'], + widgets=['bacon']) + self.assertEqual(form.Meta.exclude, [self.mock_exclude]) + self.assertEqual(form.Meta.formsets, ['baz']) + self.assertEqual(form.Meta.exclude_formsets, ['quux']) + self.assertEqual(form.Meta.widgets, ['bacon']) + + +class TestExtractPanelDefinitionsFromModelClass(TestCase): + class FakePage(Page): + pass + + def test_can_extract_panels(self): + mock = MagicMock() + mock.panels = 'foo' + result = extract_panel_definitions_from_model_class(mock) + self.assertEqual(result, 'foo') + + def test_exclude(self): + panels = extract_panel_definitions_from_model_class(Site, exclude=['hostname']) + for panel in panels: + self.assertNotEqual(panel.field_name, 'hostname') + + def test_extracted_objects_are_panels(self): + panels = extract_panel_definitions_from_model_class(self.FakePage) + for panel in panels: + self.assertTrue(issubclass(panel, BaseFieldPanel)) + + +class TestEditHandler(TestCase): + class FakeForm(dict): + def __init__(self, *args, **kwargs): + self.fields = self.fields_iterator() + + def fields_iterator(self): + for i in self: + yield i + + def setUp(self): + self.edit_handler = EditHandler(form=True, instance=True) + self.edit_handler.render = lambda: "foo" + + def test_widget_overrides(self): + result = EditHandler.widget_overrides() + self.assertEqual(result, {}) + + def test_required_formsets(self): + result = EditHandler.required_formsets() + self.assertEqual(result, []) + + def test_get_form_class(self): + result = EditHandler.get_form_class(Page) + self.assertTrue(issubclass(result, WagtailAdminModelForm)) + + def test_edit_handler_init_no_instance(self): + self.assertRaises(ValueError, EditHandler, form=True) + + def test_edit_handler_init_no_form(self): + self.assertRaises(ValueError, EditHandler, instance=True) + + def test_object_classnames(self): + result = self.edit_handler.object_classnames() + self.assertEqual(result, "") + + def test_field_classnames(self): + result = self.edit_handler.field_classnames() + self.assertEqual(result, "") + + def test_field_type(self): + result = self.edit_handler.field_type() + self.assertEqual(result, "") + + def test_render_as_object(self): + result = self.edit_handler.render_as_object() + self.assertEqual(result, "foo") + + def test_render_as_field(self): + result = self.edit_handler.render_as_field() + self.assertEqual(result, "foo") + + def test_render_js(self): + result = self.edit_handler.render_js() + self.assertEqual(result, "") + + def test_rendered_fields(self): + result = self.edit_handler.rendered_fields() + self.assertEqual(result, []) + + def test_render_missing_fields(self): + fake_form = self.FakeForm() + fake_form["foo"] = "bar" + self.edit_handler.form = fake_form + self.assertEqual(self.edit_handler.render_missing_fields(), "bar") + + def test_render_form_content(self): + fake_form = self.FakeForm() + fake_form["foo"] = "bar" + self.edit_handler.form = fake_form + self.assertEqual(self.edit_handler.render_form_content(), "foobar") + + +class TestBaseCompositeEditHandler(TestCase): + def setUp(self): + mock = MagicMock() + mock.widget_overrides.return_value = {'foo': 'bar'} + mock.required_formsets.return_value = {'baz': 'quux'} + BaseCompositeEditHandler.children = [mock] + self.base_composite_edit_handler = BaseCompositeEditHandler( + instance=True, + form=True) + + def tearDown(self): + BaseCompositeEditHandler.children = None + + def test_object_classnames_no_classname(self): + result = self.base_composite_edit_handler.object_classnames() + self.assertEqual(result, "multi-field") + + def test_object_classnames(self): + self.base_composite_edit_handler.classname = "foo" + result = self.base_composite_edit_handler.object_classnames() + self.assertEqual(result, "multi-field foo") + + def test_widget_overrides(self): + result = self.base_composite_edit_handler.widget_overrides() + self.assertEqual(result, {'foo': 'bar'}) + + def test_required_formsets(self): + result = self.base_composite_edit_handler.required_formsets() + self.assertEqual(result, ['baz']) + + +class TestBaseTabbedInterface(TestCase): + class FakeChild(object): + class FakeGrandchild(object): + def render_js(self): + return "foo" + + def rendered_fields(self): + return ["bar"] + + def __call__(self, *args, **kwargs): + fake_grandchild = self.FakeGrandchild() + return fake_grandchild + + def test_render(self): + mock = MagicMock() + BaseTabbedInterface.children = [mock] + self.base_tabbed_interface = BaseTabbedInterface( + instance=True, + form=True) + result = self.base_tabbed_interface.render() + self.assertRegexpMatches(result, 'label') + self.assertRegexpMatches(result, + '
  • ') + self.assertRegexpMatches(result, + '

    ') + + def test_render_js(self): + field = self.FakeField() + bound_field = self.FakeField() + widget = FriendlyDateInput() + field.widget = widget + bound_field.field = field + self.field_panel.bound_field = bound_field + result = self.field_panel.render_js() + self.assertEqual(result, + "initFriendlyDateChooser(fixPrefix('id for label'));") + + def test_render_js_unknown_widget(self): + field = self.FakeField() + bound_field = self.FakeField() + widget = self.FakeField() + field.widget = widget + bound_field.field = field + self.field_panel.bound_field = bound_field + result = self.field_panel.render_js() + self.assertEqual(result, + '') + + def test_render_as_field(self): + field = self.FakeField() + bound_field = self.FakeField() + bound_field.field = field + self.field_panel.bound_field = bound_field + result = self.field_panel.render_as_field() + self.assertRegexpMatches(result, + '

    help text

    ') + self.assertRegexpMatches(result, + 'errors') + + def test_rendered_fields(self): + result = self.field_panel.rendered_fields() + self.assertEqual(result, ['barbecue']) + + +class TestRichTextFieldPanel(TestCase): + class FakeField(object): + label = 'label' + help_text = 'help text' + errors = ['errors'] + id_for_label = 'id for label' + + def test_render_js(self): + fake_field = self.FakeField() + rich_text_field_panel = RichTextFieldPanel('barbecue')( + instance=True, + form={'barbecue': fake_field}) + result = rich_text_field_panel.render_js() + self.assertEqual(result, + "makeRichTextEditable(fixPrefix('id for label'));") + + +class TestPageChooserPanel(TestCase): + class FakeField(object): + label = 'label' + help_text = 'help text' + errors = ['errors'] + id_for_label = 'id for label' + + class FakeInstance(object): + class FakePage(object): + class FakeParent(object): + id = 1 + + def get_parent(self): + return self.FakeParent() + + def __init__(self): + fake_page = self.FakePage() + self.barbecue = fake_page + + + def setUp(self): + fake_field = self.FakeField() + fake_instance = self.FakeInstance() + self.page_chooser_panel = PageChooserPanel('barbecue')( + instance=fake_instance, + form={'barbecue': fake_field}) + + def test_render_js(self): + result = self.page_chooser_panel.render_js() + self.assertEqual(result, "createPageChooser(fixPrefix('id for label'), 'wagtailcore.page', 1);") From e40dea8d28358f6dbd7ee736052c8b1f8c741faf Mon Sep 17 00:00:00 2001 From: Tom Dyson Date: Wed, 18 Jun 2014 17:17:14 +0100 Subject: [PATCH 143/293] wagtail -> Wagtail in contributing.rst --- docs/contributing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index e8e42f1352c..f5eb168b2c4 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -20,7 +20,7 @@ Coding guidelines Styleguide ~~~~~~~~~~ -Developers working on the wagtail UI or creating new UI components may wish to test their work against the Styleguide, which is provided as the contrib module "wagtailstyleguide". +Developers working on the Wagtail UI or creating new UI components may wish to test their work against our Styleguide, which is provided as the contrib module "wagtailstyleguide". To install the styleguide module on your site, add it to the list of ``INSTALLED_APPS`` in your settings: @@ -34,7 +34,7 @@ To install the styleguide module on your site, add it to the list of ``INSTALLED At present the styleguide is static: new UI components must be added to it manually, and there are no hooks into it for other modules to use. We hope to support hooks in the future. -The styleguide doesn't currently provide examples of all the core interface components, notably the Page, Document, Image and Snippet chooser interfaces are not currently represented. +The styleguide doesn't currently provide examples of all the core interface components; notably the Page, Document, Image and Snippet chooser interfaces are not currently represented. Translations From 9a1da28c38096c360a056aa1c26595382d7e3792 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 17:22:46 +0100 Subject: [PATCH 144/293] Changelog entries for #236, #286 and #315 --- CHANGELOG.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index ddd41d76eb2..039935b439a 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -9,6 +9,9 @@ Changelog * Removed the "More" section from the admin menu * Added pagination to page listings in admin * Support for setting a subpage_types property on page models, to define which page types are allowed as subpages + * Added a new datetime picker + * Added styleguide + * Aesthetic improvements to preview experience * Fix: Animated GIFs are now coalesced before resizing * Fix: Wand backend clones images before modifying them * Fix: Admin breadcrumb now positioned correctly on mobile From 06dc598d0a928109aee35517f6bd161bcaf64ba8 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Wed, 18 Jun 2014 17:25:58 +0100 Subject: [PATCH 145/293] Update CHANGELOG.txt --- CHANGELOG.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 039935b439a..6686cf973ef 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -9,8 +9,8 @@ Changelog * Removed the "More" section from the admin menu * Added pagination to page listings in admin * Support for setting a subpage_types property on page models, to define which page types are allowed as subpages - * Added a new datetime picker - * Added styleguide + * Added a new datetime picker widget + * Added styleguide (mainly for wagtail developers) * Aesthetic improvements to preview experience * Fix: Animated GIFs are now coalesced before resizing * Fix: Wand backend clones images before modifying them From d95763251d5f70f819656fafeadcf3c7fb6c2603 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Wed, 18 Jun 2014 17:29:24 +0100 Subject: [PATCH 146/293] Corrected names of userbar tests --- wagtail/wagtailadmin/tests/test_userbar.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wagtail/wagtailadmin/tests/test_userbar.py b/wagtail/wagtailadmin/tests/test_userbar.py index 52ec2d60ad6..acdb81690eb 100644 --- a/wagtail/wagtailadmin/tests/test_userbar.py +++ b/wagtail/wagtailadmin/tests/test_userbar.py @@ -49,7 +49,7 @@ def test_userbar_frontend(self): self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailadmin/userbar/base.html') - def test_userbar_anonymous_user_cannot_see(self): + def test_userbar_frontend_anonymous_user_cannot_see(self): # Logout self.client.logout() @@ -66,13 +66,13 @@ def setUp(self): self.homepage.save_revision() self.revision = self.homepage.get_latest_revision() - def test_userbar_frontend(self): + def test_userbar_moderation(self): response = self.client.get(reverse('wagtailadmin_userbar_moderation', args=(self.revision.id, ))) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'wagtailadmin/userbar/base.html') - def test_userbar_anonymous_user_cannot_see(self): + def test_userbar_moderation_anonymous_user_cannot_see(self): # Logout self.client.logout() From cd06b2c6e22666f523716866c9663d4012b2aae1 Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Wed, 18 Jun 2014 17:33:20 +0100 Subject: [PATCH 147/293] Remove broken test --- wagtail/wagtailadmin/tests/test_edit_handlers.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py index 8e0e4a7c54b..cd21748b459 100644 --- a/wagtail/wagtailadmin/tests/test_edit_handlers.py +++ b/wagtail/wagtailadmin/tests/test_edit_handlers.py @@ -287,17 +287,6 @@ def test_render_as_object(self): self.assertRegexpMatches(result, '

    ') - def test_render_js(self): - field = self.FakeField() - bound_field = self.FakeField() - widget = FriendlyDateInput() - field.widget = widget - bound_field.field = field - self.field_panel.bound_field = bound_field - result = self.field_panel.render_js() - self.assertEqual(result, - "initFriendlyDateChooser(fixPrefix('id for label'));") - def test_render_js_unknown_widget(self): field = self.FakeField() bound_field = self.FakeField() From 9a5954607d4ddc232991e493d61484e3fb2fbdcb Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Thu, 19 Jun 2014 10:28:56 +0100 Subject: [PATCH 148/293] Renamed pageurl tags to wagtailcore_tags --- wagtail/wagtailcore/templatetags/pageurl.py | 26 ++++--------------- .../templatetags/wagtailcore_tags.py | 25 ++++++++++++++++++ 2 files changed, 30 insertions(+), 21 deletions(-) create mode 100644 wagtail/wagtailcore/templatetags/wagtailcore_tags.py diff --git a/wagtail/wagtailcore/templatetags/pageurl.py b/wagtail/wagtailcore/templatetags/pageurl.py index d3488d9b459..fe64a302f6a 100644 --- a/wagtail/wagtailcore/templatetags/pageurl.py +++ b/wagtail/wagtailcore/templatetags/pageurl.py @@ -1,24 +1,8 @@ -from django import template +import warnings -from wagtail.wagtailcore.models import Page +warnings.warn( + "The pageurl tags has been renamed. " + "Use wagtailcore_tags instead.", DeprecationWarning) -register = template.Library() - -@register.simple_tag(takes_context=True) -def pageurl(context, page): - """ - Outputs a page's URL as relative (/foo/bar/) if it's within the same site as the - current page, or absolute (http://example.com/foo/bar/) if not. - """ - return page.relative_url(context['request'].site) - -@register.simple_tag(takes_context=True) -def slugurl(context, slug): - """Returns the URL for the page that has the given slug.""" - page = Page.objects.filter(slug=slug).first() - - if page: - return page.relative_url(context['request'].site) - else: - return None +from wagtail.wagtailcore.templatetags.wagtailcore_tags import register diff --git a/wagtail/wagtailcore/templatetags/wagtailcore_tags.py b/wagtail/wagtailcore/templatetags/wagtailcore_tags.py new file mode 100644 index 00000000000..d91c05742df --- /dev/null +++ b/wagtail/wagtailcore/templatetags/wagtailcore_tags.py @@ -0,0 +1,25 @@ +from django import template + +from wagtail.wagtailcore.models import Page + +register = template.Library() + + +@register.simple_tag(takes_context=True) +def pageurl(context, page): + """ + Outputs a page's URL as relative (/foo/bar/) if it's within the same site as the + current page, or absolute (http://example.com/foo/bar/) if not. + """ + return page.relative_url(context['request'].site) + + +@register.simple_tag(takes_context=True) +def slugurl(context, slug): + """Returns the URL for the page that has the given slug.""" + page = Page.objects.filter(slug=slug).first() + + if page: + return page.relative_url(context['request'].site) + else: + return None From 122abc9a8c7a332b623b86e7a5c6d9bdb28ac4b4 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Thu, 19 Jun 2014 10:30:09 +0100 Subject: [PATCH 149/293] renamed rich_text tags to wagtailrichtext_tags --- wagtail/wagtailcore/templatetags/rich_text.py | 13 +++++-------- .../templatetags/wagtailrichtext_tags.py | 11 +++++++++++ 2 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 wagtail/wagtailcore/templatetags/wagtailrichtext_tags.py diff --git a/wagtail/wagtailcore/templatetags/rich_text.py b/wagtail/wagtailcore/templatetags/rich_text.py index d3bc64fddcb..d7d16264504 100644 --- a/wagtail/wagtailcore/templatetags/rich_text.py +++ b/wagtail/wagtailcore/templatetags/rich_text.py @@ -1,11 +1,8 @@ -from django import template -from django.utils.safestring import mark_safe +import warnings -from wagtail.wagtailcore.rich_text import expand_db_html +warnings.warn( + "The rich_text tags has been renamed. " + "Use wagtailrichtext_tags instead.", DeprecationWarning) -register = template.Library() - -@register.filter -def richtext(value): - return mark_safe('

    ' + expand_db_html(value) + '
    ') +from wagtail.wagtailcore.templatetags.wagtailrichtext_tags import register diff --git a/wagtail/wagtailcore/templatetags/wagtailrichtext_tags.py b/wagtail/wagtailcore/templatetags/wagtailrichtext_tags.py new file mode 100644 index 00000000000..d3bc64fddcb --- /dev/null +++ b/wagtail/wagtailcore/templatetags/wagtailrichtext_tags.py @@ -0,0 +1,11 @@ +from django import template +from django.utils.safestring import mark_safe + +from wagtail.wagtailcore.rich_text import expand_db_html + +register = template.Library() + + +@register.filter +def richtext(value): + return mark_safe('
    ' + expand_db_html(value) + '
    ') From 65ec6d77e8effdf54aefcb6d5b42f65ba2089436 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Thu, 19 Jun 2014 10:36:03 +0100 Subject: [PATCH 150/293] Merged richtext tags into wagtailcore_tags --- wagtail/wagtailcore/templatetags/rich_text.py | 4 ++-- wagtail/wagtailcore/templatetags/wagtailcore_tags.py | 7 +++++++ .../wagtailcore/templatetags/wagtailrichtext_tags.py | 11 ----------- 3 files changed, 9 insertions(+), 13 deletions(-) delete mode 100644 wagtail/wagtailcore/templatetags/wagtailrichtext_tags.py diff --git a/wagtail/wagtailcore/templatetags/rich_text.py b/wagtail/wagtailcore/templatetags/rich_text.py index d7d16264504..94c2d176c1e 100644 --- a/wagtail/wagtailcore/templatetags/rich_text.py +++ b/wagtail/wagtailcore/templatetags/rich_text.py @@ -2,7 +2,7 @@ warnings.warn( "The rich_text tags has been renamed. " - "Use wagtailrichtext_tags instead.", DeprecationWarning) + "Use wagtailcore_tags instead.", DeprecationWarning) -from wagtail.wagtailcore.templatetags.wagtailrichtext_tags import register +from wagtail.wagtailcore.templatetags.wagtailcore_tags import register diff --git a/wagtail/wagtailcore/templatetags/wagtailcore_tags.py b/wagtail/wagtailcore/templatetags/wagtailcore_tags.py index d91c05742df..5e137c7a2ef 100644 --- a/wagtail/wagtailcore/templatetags/wagtailcore_tags.py +++ b/wagtail/wagtailcore/templatetags/wagtailcore_tags.py @@ -1,6 +1,8 @@ from django import template +from django.utils.safestring import mark_safe from wagtail.wagtailcore.models import Page +from wagtail.wagtailcore.rich_text import expand_db_html register = template.Library() @@ -23,3 +25,8 @@ def slugurl(context, slug): return page.relative_url(context['request'].site) else: return None + + +@register.filter +def richtext(value): + return mark_safe('
    ' + expand_db_html(value) + '
    ') diff --git a/wagtail/wagtailcore/templatetags/wagtailrichtext_tags.py b/wagtail/wagtailcore/templatetags/wagtailrichtext_tags.py deleted file mode 100644 index d3bc64fddcb..00000000000 --- a/wagtail/wagtailcore/templatetags/wagtailrichtext_tags.py +++ /dev/null @@ -1,11 +0,0 @@ -from django import template -from django.utils.safestring import mark_safe - -from wagtail.wagtailcore.rich_text import expand_db_html - -register = template.Library() - - -@register.filter -def richtext(value): - return mark_safe('
    ' + expand_db_html(value) + '
    ') From b3e79519329dc9f2b3ebd94405b3e84024dc8353 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Thu, 19 Jun 2014 10:39:50 +0100 Subject: [PATCH 151/293] Moved embed_filters to wagtailembeds_tags --- .../templatetags/embed_filters.py | 26 ++++------------- .../templatetags/wagtailembeds_tags.py | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+), 21 deletions(-) create mode 100644 wagtail/wagtailembeds/templatetags/wagtailembeds_tags.py diff --git a/wagtail/wagtailembeds/templatetags/embed_filters.py b/wagtail/wagtailembeds/templatetags/embed_filters.py index d916c0ffbab..25326fec607 100644 --- a/wagtail/wagtailembeds/templatetags/embed_filters.py +++ b/wagtail/wagtailembeds/templatetags/embed_filters.py @@ -1,24 +1,8 @@ -from django import template -from django.utils.safestring import mark_safe +import warnings -from wagtail.wagtailembeds import get_embed +warnings.warn( + "The embed_filters tags has been renamed. " + "Use wagtailembeds_tags instead.", DeprecationWarning) -register = template.Library() - - -@register.filter -def embed(url, max_width=None): - embed = get_embed(url, max_width=max_width) - try: - if embed is not None: - return mark_safe(embed.html) - else: - return '' - except: - return '' - - -@register.filter -def embedly(url, max_width=None): - return embed(url, max_width) +from wagtail.wagtailembeds.templatetags.wagtailembeds_tags import register diff --git a/wagtail/wagtailembeds/templatetags/wagtailembeds_tags.py b/wagtail/wagtailembeds/templatetags/wagtailembeds_tags.py new file mode 100644 index 00000000000..aad751c6a60 --- /dev/null +++ b/wagtail/wagtailembeds/templatetags/wagtailembeds_tags.py @@ -0,0 +1,28 @@ +from django import template +from django.utils.safestring import mark_safe + +from wagtail.wagtailembeds import get_embed + + +register = template.Library() + + +@register.filter +def embed(url, max_width=None): + embed = get_embed(url, max_width=max_width) + try: + if embed is not None: + return mark_safe(embed.html) + else: + return '' + except: + return '' + + +@register.filter +def embedly(url, max_width=None): + warnings.warn( + "The 'embedly' filter has been renamed. " + "Use 'embed' instead.", DeprecationWarning) + + return embed(url, max_width) From 008b3238abfb874e520c7cad0349fc55441aca6f Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Thu, 19 Jun 2014 10:41:53 +0100 Subject: [PATCH 152/293] Moved image_tags to wagtailimages_tags --- .../wagtailimages/templatetags/image_tags.py | 71 ++----------------- .../templatetags/wagtailimages_tags.py | 69 ++++++++++++++++++ 2 files changed, 74 insertions(+), 66 deletions(-) create mode 100644 wagtail/wagtailimages/templatetags/wagtailimages_tags.py diff --git a/wagtail/wagtailimages/templatetags/image_tags.py b/wagtail/wagtailimages/templatetags/image_tags.py index e59d9cd1486..7eba192d463 100644 --- a/wagtail/wagtailimages/templatetags/image_tags.py +++ b/wagtail/wagtailimages/templatetags/image_tags.py @@ -1,69 +1,8 @@ -from django import template +import warnings -from wagtail.wagtailimages.models import Filter +warnings.warn( + "The image_tags tags has been renamed. " + "Use wagtailimages_tags instead.", DeprecationWarning) -register = template.Library() -# Local cache of filters, avoid hitting the DB -filters = {} - -@register.tag(name="image") -def image(parser, token): - args = token.split_contents() - - if len(args) == 3: - # token is of the form {% image self.photo max-320x200 %} - tag_name, image_var, filter_spec = args - return ImageNode(image_var, filter_spec) - - elif len(args) == 5: - # token is of the form {% image self.photo max-320x200 as img %} - tag_name, image_var, filter_spec, as_token, out_var = args - - if as_token != 'as': - raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 %%} or {%% image self.photo max-320x200 as img %%}") - - return ImageNode(image_var, filter_spec, out_var) - - else: - raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 %%} or {%% image self.photo max-320x200 as img %%}") - - -class ImageNode(template.Node): - def __init__(self, image_var_name, filter_spec, output_var_name=None): - self.image_var = template.Variable(image_var_name) - self.output_var_name = output_var_name - - if filter_spec not in filters: - filters[filter_spec], _ = Filter.objects.get_or_create(spec=filter_spec) - self.filter = filters[filter_spec] - - def render(self, context): - try: - image = self.image_var.resolve(context) - except template.VariableDoesNotExist: - return '' - - if not image: - return '' - - try: - rendition = image.get_rendition(self.filter) - except IOError: - # It's fairly routine for people to pull down remote databases to their - # local dev versions without retrieving the corresponding image files. - # In such a case, we would get an IOError at the point where we try to - # create the resized version of a non-existent image. Since this is a - # bit catastrophic for a missing image, we'll substitute a dummy - # Rendition object so that we just output a broken link instead. - Rendition = image.renditions.model # pick up any custom Image / Rendition classes that may be in use - rendition = Rendition(image=image, width=0, height=0) - rendition.file.name = 'not-found' - - if self.output_var_name: - # return the rendition object in the given variable - context[self.output_var_name] = rendition - return '' - else: - # render the rendition's image tag now - return rendition.img_tag() +from wagtail.wagtailimages.templatetags.wagtailimages_tags import register diff --git a/wagtail/wagtailimages/templatetags/wagtailimages_tags.py b/wagtail/wagtailimages/templatetags/wagtailimages_tags.py new file mode 100644 index 00000000000..e59d9cd1486 --- /dev/null +++ b/wagtail/wagtailimages/templatetags/wagtailimages_tags.py @@ -0,0 +1,69 @@ +from django import template + +from wagtail.wagtailimages.models import Filter + +register = template.Library() + +# Local cache of filters, avoid hitting the DB +filters = {} + +@register.tag(name="image") +def image(parser, token): + args = token.split_contents() + + if len(args) == 3: + # token is of the form {% image self.photo max-320x200 %} + tag_name, image_var, filter_spec = args + return ImageNode(image_var, filter_spec) + + elif len(args) == 5: + # token is of the form {% image self.photo max-320x200 as img %} + tag_name, image_var, filter_spec, as_token, out_var = args + + if as_token != 'as': + raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 %%} or {%% image self.photo max-320x200 as img %%}") + + return ImageNode(image_var, filter_spec, out_var) + + else: + raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 %%} or {%% image self.photo max-320x200 as img %%}") + + +class ImageNode(template.Node): + def __init__(self, image_var_name, filter_spec, output_var_name=None): + self.image_var = template.Variable(image_var_name) + self.output_var_name = output_var_name + + if filter_spec not in filters: + filters[filter_spec], _ = Filter.objects.get_or_create(spec=filter_spec) + self.filter = filters[filter_spec] + + def render(self, context): + try: + image = self.image_var.resolve(context) + except template.VariableDoesNotExist: + return '' + + if not image: + return '' + + try: + rendition = image.get_rendition(self.filter) + except IOError: + # It's fairly routine for people to pull down remote databases to their + # local dev versions without retrieving the corresponding image files. + # In such a case, we would get an IOError at the point where we try to + # create the resized version of a non-existent image. Since this is a + # bit catastrophic for a missing image, we'll substitute a dummy + # Rendition object so that we just output a broken link instead. + Rendition = image.renditions.model # pick up any custom Image / Rendition classes that may be in use + rendition = Rendition(image=image, width=0, height=0) + rendition.file.name = 'not-found' + + if self.output_var_name: + # return the rendition object in the given variable + context[self.output_var_name] = rendition + return '' + else: + # render the rendition's image tag now + return rendition.img_tag() From f73c7da7728f92cd07702de89cd31544db5fff7f Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Thu, 19 Jun 2014 11:17:32 +0100 Subject: [PATCH 153/293] Update docs to import tags from correct tags module --- docs/building_your_site/frontenddevelopers.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/building_your_site/frontenddevelopers.rst b/docs/building_your_site/frontenddevelopers.rst index f0054eaab59..704708e0cdf 100644 --- a/docs/building_your_site/frontenddevelopers.rst +++ b/docs/building_your_site/frontenddevelopers.rst @@ -100,7 +100,7 @@ For example: .. code-block:: django - {% load image %} + {% load wagtailimages_tags %} ... {% image self.photo width-400 %} @@ -190,7 +190,7 @@ In some cases greater control over the ``img`` tag is required, for example to a .. code-block:: django - {% load image %} + {% load wagtailimages_tags %} ... {% image self.photo width-400 as tmp_photo %} @@ -209,7 +209,7 @@ Only fields using ``RichTextField`` need this applied in the template. .. code-block:: django - {% load rich_text %} + {% load wagtailcore_tags %} ... {{ self.body|richtext }} @@ -252,7 +252,7 @@ Takes a Page object and returns a relative URL (``/foo/bar/``) if within the sam .. code-block:: django - {% load pageurl %} + {% load wagtailcore_tags %} ... @@ -263,7 +263,7 @@ Takes any ``slug`` as defined in a page's "Promote" tab and returns the URL for .. code-block:: django - {% load slugurl %} + {% load wagtailcore_tags %} ... From 879269ab20e69894c8e947892101f9eba3669471 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Thu, 19 Jun 2014 11:22:58 +0100 Subject: [PATCH 154/293] Added versionchanged notes to docs --- docs/building_your_site/frontenddevelopers.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/building_your_site/frontenddevelopers.rst b/docs/building_your_site/frontenddevelopers.rst index 704708e0cdf..0ef918582df 100644 --- a/docs/building_your_site/frontenddevelopers.rst +++ b/docs/building_your_site/frontenddevelopers.rst @@ -90,6 +90,9 @@ In addition to Django's standard tags and filters, Wagtail provides some of its Images (tag) ~~~~~~~~~~~~ +.. versionchanged:: 0.4 + The 'image_tags' tags library was renamed to 'wagtailimages_tags' + The ``image`` tag inserts an XHTML-compatible ``img`` element into the page, setting its ``src``, ``width``, ``height`` and ``alt``. See also :ref:`image_tag_alt`. The syntax for the tag is thus:: @@ -203,6 +206,9 @@ In some cases greater control over the ``img`` tag is required, for example to a Rich text (filter) ~~~~~~~~~~~~~~~~~~ +.. versionchanged:: 0.4 + The 'rich_text' tags library was renamed to 'wagtailcore_tags' + This filter takes a chunk of HTML content and renders it as safe HTML in the page. Importantly it also expands internal shorthand references to embedded images and links made in the Wagtail editor into fully-baked HTML ready for display. Only fields using ``RichTextField`` need this applied in the template. @@ -245,6 +251,9 @@ Wagtail embeds and images are included at their full width, which may overflow t Internal links (tag) ~~~~~~~~~~~~~~~~~~~~ +.. versionchanged:: 0.4 + The 'pageurl' tags library was renamed to 'wagtailcore_tags' + pageurl -------- From 03ce91c992c1c8d2dc49649d10b35add650fbd90 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 19 Jun 2014 12:28:07 +0100 Subject: [PATCH 155/293] Update CONTRIBUTORS.rst --- CONTRIBUTORS.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index a3f9c7221d5..fcba8d2d7f9 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -1,8 +1,8 @@ Original Authors ================ -* Matthew Westcott matthew.westcott@torchbox.com -* David Cranwell david.cranwell@torchbox.com +* Matthew Westcott matthew.westcott@torchbox.com twitter: @gasmanic +* David Cranwell david.cranwell@torchbox.com twitter: @davecranwell * Karl Hobley karl.hobley@torchbox.com * Helen Chapman helen.chapman@torchbox.com From 6a33834d2948d69ce75c8ef3413cb9acc093557f Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 19 Jun 2014 13:30:39 +0100 Subject: [PATCH 156/293] ongoing styling of tabs an publishing fields, inc introduction of salmon colour --- .../templates/wagtailstyleguide/base.html | 13 +++++++--- wagtail/wagtailadmin/edit_handlers.py | 17 ++++++++++-- .../wagtailadmin/scss/components/forms.scss | 8 ++++++ .../wagtailadmin/scss/components/tabs.scss | 5 ++-- .../scss/layouts/page-editor.scss | 26 +++++++++++++------ .../wagtailadmin/scss/layouts/styleguide.scss | 6 +++++ .../static/wagtailadmin/scss/variables.scss | 2 ++ 7 files changed, 61 insertions(+), 16 deletions(-) diff --git a/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html b/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html index e7bd8860611..e0d478fe1bf 100644 --- a/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html +++ b/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html @@ -42,9 +42,10 @@

    Colour palette

  • color-teal
  • color-teal-darker
  • color-teal-dark
  • -
  • color-red
  • -
  • color-orange
  • -
  • color-green
  • + +
      +
    • color-salmon
    • +
    • color-salmon-light
    • color-grey-1
    • @@ -54,6 +55,12 @@

      Colour palette

    • color-grey-4
    • color-grey-5
    +
      +
    • color-red
    • +
    • color-orange
    • +
    • color-green
    • +
    +
    diff --git a/wagtail/wagtailadmin/edit_handlers.py b/wagtail/wagtailadmin/edit_handlers.py index 175c63225f9..bfdeaf8129b 100644 --- a/wagtail/wagtailadmin/edit_handlers.py +++ b/wagtail/wagtailadmin/edit_handlers.py @@ -602,17 +602,30 @@ def InlinePanel(base_model, relation_name, panels=None, label='', help_text=''): }) +# This allows users to include the publishing panel in their own per-model override +# without having to write these fields out by hand, potentially losing 'classname' +# and therefore the associated styling of the publishing panel +def PublishingPanel(): + return MultiFieldPanel([ + FieldPanel('go_live_at'), + FieldPanel('expire_at'), + ], ugettext_lazy('Scheduled publishing'), classname="publishing") + + # Now that we've defined EditHandlers, we can set up wagtailcore.Page to have some. Page.content_panels = [ FieldPanel('title', classname="full title"), ] + Page.promote_panels = [ MultiFieldPanel([ FieldPanel('slug'), FieldPanel('seo_title'), FieldPanel('show_in_menus'), FieldPanel('search_description'), - FieldPanel('go_live_at'), - FieldPanel('expire_at'), ], ugettext_lazy('Common page configuration')), ] + +Page.settings_panels = [ + PublishingPanel() +] diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss index 5a870fbcf52..0327c940af9 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss @@ -1,3 +1,9 @@ +/* + These are the generic stylings for forms of any type. + If you're styling something specific to the page editing interface, + it probably ought to go in layouts/page-editor.scss +*/ + form { ul, li{ list-style-type:none; @@ -292,6 +298,7 @@ button.icon{ overflow:hidden; > li{ + @include row(); position:relative; background-color:white; padding:1em 10em 1em 1.5em; /* 10em padding leaves room for controls */ @@ -447,6 +454,7 @@ li.focused > .help{ } } + .fields li{ @include row(); padding-top:0.5em; diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss index af0c496b113..dab30d114a3 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/tabs.scss @@ -2,7 +2,6 @@ @include row(); padding:0; background:$color-grey-4; - overflow:hidden; li{ list-style-type:none; @@ -22,10 +21,10 @@ text-decoration:none; display:block; padding:0.7em; - padding-bottom:1em; - margin-bottom:-0.3em; color:white; border-top:0.3em solid lighten($color-teal-darker, 3%); + max-height:1.2em; + overflow:hidden; &:hover{ color:white; diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/page-editor.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/page-editor.scss index 5e3120c8248..c9fe5b54b04 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/page-editor.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/page-editor.scss @@ -25,9 +25,6 @@ } } -.objects{ - background:url("#{$static-root}bg-dark-diag.svg"); -} .object{ position:relative; overflow:hidden; @@ -80,7 +77,7 @@ > h2, &.single-field label{ -webkit-font-smoothing: auto; - background:$color-grey-3; + background:$color-salmon-light; text-transform:uppercase; padding:0.9em 0 0.9em 4em; font-size:0.95em; @@ -92,10 +89,10 @@ left:0; right:0; z-index:1; - text-shadow:1px 1px 1px rgba(255,255,255,0.5); - @include box-shadow(0 0 7px 0 rgba(0,0,0,0.4)); + overflow:hidden; &:before{ + text-shadow:none; font-family:wagtail; text-transform:none; content:"q"; @@ -108,10 +105,11 @@ line-height:1.8em; left:0px; width:1.7em; - opacity:0.15; + color:white; padding:0; margin:0; cursor:pointer; + background-color:$color-salmon; } } @@ -186,6 +184,17 @@ } } + /* special panel for the publishing fields, requires a bit more pizzazz */ + &.publishing{ + h2:before{ + content:"7"; + font-size:2.5em; + line-height:1.4em; + width:1.3em; + } + + } + &.title input, &.title textarea{ font-size:2em; @@ -235,16 +244,17 @@ top:0px; left:0px; width:3.3em; - background-color:$color-teal; padding:0; margin:0 0 0 -20px; cursor:pointer; a{ + @include border-radius(0); font-size: 0em; line-height: 0; overflow: visible; display:block; + background-color:$color-salmon; &:before{ position:relative; diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss index 38d4281da9a..09cb627edb7 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/styleguide.scss @@ -68,6 +68,12 @@ section{ .color-grey-5{ background-color:$color-grey-5; } + .color-salmon{ + background-color:$color-salmon; + } + .color-salmon-light{ + background-color:$color-salmon-light; + } } diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss index 0f65679893f..9479b8a28a5 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss @@ -30,6 +30,8 @@ $color-teal-dark: #246060; $color-red: #f7474e; $color-orange:#e9b04d; $color-green: #189370; +$color-salmon: #f37e77; +$color-salmon-light: #fcf2f2; /* darker to lighter */ $color-grey-1: #333333; From d1b321f859e3a9f19e636c9ec4a0af9ac4992b27 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 19 Jun 2014 13:33:48 +0100 Subject: [PATCH 157/293] made red more distinct from salmon --- wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss index 9479b8a28a5..e27817175fc 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/variables.scss @@ -27,7 +27,7 @@ $breakpoint-desktop-larger: 100em; /* 1600px */ $color-teal: #43b1b0; $color-teal-darker: darken($color-teal, 10%); $color-teal-dark: #246060; -$color-red: #f7474e; +$color-red: #cd3238; $color-orange:#e9b04d; $color-green: #189370; $color-salmon: #f37e77; From 62fc679720aeb18c79e9d17fa5e4c6b67b105340 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 19 Jun 2014 13:47:09 +0100 Subject: [PATCH 158/293] further tweaks to colours and form layout --- .../static/wagtailadmin/scss/components/datetimepicker.scss | 2 +- .../static/wagtailadmin/scss/components/forms.scss | 2 +- .../static/wagtailadmin/scss/layouts/page-editor.scss | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/datetimepicker.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/datetimepicker.scss index 078c9346999..4902c241830 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/datetimepicker.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/datetimepicker.scss @@ -246,7 +246,7 @@ .xdsoft_calendar td.xdsoft_default, .xdsoft_calendar td.xdsoft_current, .xdsoft_timepicker .xdsoft_time_box > div > div.xdsoft_current{ - background: $color-orange; + background: $color-salmon; color:#fff; font-weight: 700; } diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss index 0327c940af9..1d9b8b7a734 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/components/forms.scss @@ -456,7 +456,7 @@ li.focused > .help{ .fields li{ - @include row(); + @include clearfix(); padding-top:0.5em; padding-bottom:1.2em; } diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/page-editor.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/page-editor.scss index c9fe5b54b04..c75f0b6bcf9 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/page-editor.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/page-editor.scss @@ -79,7 +79,7 @@ -webkit-font-smoothing: auto; background:$color-salmon-light; text-transform:uppercase; - padding:0.9em 0 0.9em 4em; + padding:0.9em 0 0.9em 4.1em; font-size:0.95em; margin:0 0 0.2em 0; line-height:1.5em; @@ -188,9 +188,9 @@ &.publishing{ h2:before{ content:"7"; - font-size:2.5em; + font-size:2.4em; line-height:1.4em; - width:1.3em; + width:1.4em; } } From 4c5a1b1ae9a16821bdade3fd133eaca2b1e82d18 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Thu, 19 Jun 2014 14:17:27 +0100 Subject: [PATCH 159/293] Recache coverage badge --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 62b3c5cd5ac..0e68b8c6b18 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ .. image:: https://travis-ci.org/torchbox/wagtail.png?branch=master :target: https://travis-ci.org/torchbox/wagtail -.. image:: https://coveralls.io/repos/torchbox/wagtail/badge.png?branch=master&zxcv +.. image:: https://coveralls.io/repos/torchbox/wagtail/badge.png?branch=master&zxcv1 :target: https://coveralls.io/r/torchbox/wagtail?branch=master .. image:: https://pypip.in/v/wagtail/badge.png?zxcv From 269dfe62f5517013d54810832a846ac143339b60 Mon Sep 17 00:00:00 2001 From: Dave Cranwell Date: Thu, 19 Jun 2014 16:58:48 +0100 Subject: [PATCH 160/293] refactoring how/where fields get their classes added --- .../templates/wagtailstyleguide/base.html | 1 + wagtail/contrib/wagtailstyleguide/views.py | 1 + wagtail/wagtailadmin/edit_handlers.py | 26 +-- .../wagtailadmin/scss/components/forms.scss | 99 +++++++---- .../wagtailadmin/scss/components/header.scss | 7 - .../wagtailadmin/scss/components/icons.scss | 10 +- .../scss/fonts/wagtail-icomoon.json | 164 ++++++++++-------- .../wagtailadmin/scss/fonts/wagtail.eot | Bin 25504 -> 25648 bytes .../wagtailadmin/scss/fonts/wagtail.svg | 1 + .../wagtailadmin/scss/fonts/wagtail.ttf | Bin 25340 -> 25484 bytes .../wagtailadmin/scss/fonts/wagtail.woff | Bin 15108 -> 15192 bytes .../wagtailadmin/scss/layouts/login.scss | 18 +- .../edit_handlers/chooser_panel.html | 2 +- .../edit_handlers/field_panel_field.html | 24 +-- .../edit_handlers/multi_field_panel.html | 4 +- ...el_object.html => single_field_panel.html} | 2 +- .../templates/wagtailadmin/shared/field.html | 25 +++ .../wagtailadmin/shared/field_as_li.html | 25 +-- .../templates/wagtailadmin/shared/header.html | 2 +- .../wagtailforms/index_submissions.html | 2 +- 20 files changed, 223 insertions(+), 190 deletions(-) rename wagtail/wagtailadmin/templates/wagtailadmin/edit_handlers/{field_panel_object.html => single_field_panel.html} (57%) create mode 100644 wagtail/wagtailadmin/templates/wagtailadmin/shared/field.html diff --git a/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html b/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html index e0d478fe1bf..767f69f7f10 100644 --- a/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html +++ b/wagtail/contrib/wagtailstyleguide/templates/wagtailstyleguide/base.html @@ -388,6 +388,7 @@

    Icons

  • warning
  • success
  • date
  • +
  • time
  • form
  • diff --git a/wagtail/contrib/wagtailstyleguide/views.py b/wagtail/contrib/wagtailstyleguide/views.py index 52c5433a1e7..9c830073c20 100644 --- a/wagtail/contrib/wagtailstyleguide/views.py +++ b/wagtail/contrib/wagtailstyleguide/views.py @@ -23,6 +23,7 @@ class ExampleForm(forms.Form): url = forms.URLField(required=True) email = forms.EmailField(max_length=254) date = forms.DateField() + time = forms.TimeField() select = forms.ChoiceField(choices=CHOICES) boolean = forms.BooleanField(required=False) diff --git a/wagtail/wagtailadmin/edit_handlers.py b/wagtail/wagtailadmin/edit_handlers.py index bfdeaf8129b..9ded8bb297f 100644 --- a/wagtail/wagtailadmin/edit_handlers.py +++ b/wagtail/wagtailadmin/edit_handlers.py @@ -195,9 +195,20 @@ def object_classnames(self): return "" def field_classnames(self): + classname = self.field_type() + "test" + + if self.bound_field.field.required: + classname += " required" + if self.bound_field.errors: + classname += " error" + + return classname + + + def input_classnames(self): """ - Additional classnames to add to the
  • when rendering this within a -
  • {% endblock %} diff --git a/wagtail/wagtailadmin/views/account.py b/wagtail/wagtailadmin/views/account.py index d5ab71bd6f5..c5cf6ffae8b 100644 --- a/wagtail/wagtailadmin/views/account.py +++ b/wagtail/wagtailadmin/views/account.py @@ -10,12 +10,17 @@ from wagtail.wagtailadmin import forms from wagtail.wagtailusers.forms import NotificationPreferencesForm +from wagtail.wagtailcore.models import UserPagePermissionsProxy @permission_required('wagtailadmin.access_admin') def account(request): + user_perms = UserPagePermissionsProxy(request.user) + show_notification_preferences = user_perms.can_edit_pages() or user_perms.can_publish_pages() + return render(request, 'wagtailadmin/account/account.html', { 'show_change_password': getattr(settings, 'WAGTAIL_PASSWORD_MANAGEMENT_ENABLED', True) and request.user.has_usable_password(), + 'show_notification_preferences': show_notification_preferences }) @@ -56,6 +61,11 @@ def notification_preferences(request): else: form = NotificationPreferencesForm(instance=request.user.get_profile()) + # quick-and-dirty catch-all in case the form has been rendered with no + # fields, as the user has no customisable permissions + if not form.fields: + return redirect('wagtailadmin_account') + return render(request, 'wagtailadmin/account/notification_preferences.html', { 'form': form, }) From dd7344d65d13881aa0d923f9fa0cacbaf3db1cfe Mon Sep 17 00:00:00 2001 From: Nick Smith Date: Mon, 23 Jun 2014 10:51:35 +0100 Subject: [PATCH 211/293] Add tests for notification preferences views' being filtered for less privileged users --- .../tests/test_account_management.py | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/wagtail/wagtailadmin/tests/test_account_management.py b/wagtail/wagtailadmin/tests/test_account_management.py index 56aa6356034..e8f46a25b70 100644 --- a/wagtail/wagtailadmin/tests/test_account_management.py +++ b/wagtail/wagtailadmin/tests/test_account_management.py @@ -1,7 +1,7 @@ from django.test import TestCase from wagtail.tests.utils import unittest, WagtailTestUtils from django.core.urlresolvers import reverse -from django.contrib.auth.models import User +from django.contrib.auth.models import User, Group, Permission from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.core import mail @@ -213,6 +213,62 @@ def test_notification_preferences_view_post(self): self.assertTrue(profile.rejected_notifications) +class TestAccountManagementForNonModerator(TestCase, WagtailTestUtils): + """ + Tests of reduced-functionality for editors + """ + def setUp(self): + # Create a non-moderator user + self.submitter = User.objects.create_user('submitter', 'submitter@example.com', 'password') + self.submitter.groups.add(Group.objects.get(name='Editors')) + + self.client.login(username=self.submitter.username, password='password') + + def test_notification_preferences_form_is_reduced_for_non_moderators(self): + """ + This tests that a user without publish permissions is not shown the + notification preference for 'submitted' items + """ + response = self.client.get(reverse('wagtailadmin_account_notification_preferences')) + self.assertIn('approved_notifications', response.context['form'].fields.keys()) + self.assertIn('rejected_notifications', response.context['form'].fields.keys()) + self.assertNotIn('submitted_notifications', response.context['form'].fields.keys()) + + +class TestAccountManagementForAdminOnlyUser(TestCase, WagtailTestUtils): + """ + Tests for users with no edit/publish permissions at all + """ + def setUp(self): + # Create a non-moderator user + admin_only_group = Group.objects.create(name='Admin Only') + admin_only_group.permissions.add(Permission.objects.get(codename='access_admin')) + + self.admin_only_user = User.objects.create_user('admin_only_user', 'admin_only_user@example.com', 'password') + self.admin_only_user.groups.add(admin_only_group) + + self.client.login(username=self.admin_only_user.username, password='password') + + def test_notification_preferences_view_redirects_for_admin_only_users(self): + """ + Test that the user is not shown the notification preferences view but instead + redirected to the account page + """ + response = self.client.get(reverse('wagtailadmin_account_notification_preferences')) + self.assertRedirects(response, reverse('wagtailadmin_account')) + + def test_notification_preferences_link_not_shown_for_admin_only_users(self): + """ + Test that the user is not even shown the link to the notification + preferences view + """ + response = self.client.get(reverse('wagtailadmin_account')) + self.assertEqual(response.context['show_notification_preferences'], False) + self.assertNotContains(response, reverse('wagtailadmin_account_notification_preferences')) + # safety check that checking for absence/presence of urls works + self.assertContains(response, reverse('wagtailadmin_home')) + + class TestPasswordReset(TestCase, WagtailTestUtils): """ This tests that the password reset is working From 2801c913dc3b64d41cfd5ed70ebab270e434f9df Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 23 Jun 2014 14:22:45 +0100 Subject: [PATCH 212/293] Docs update for #342 merge --- docs/wagtail_search.rst | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/wagtail_search.rst b/docs/wagtail_search.rst index 3d8ea26b234..1fa2c6525d9 100644 --- a/docs/wagtail_search.rst +++ b/docs/wagtail_search.rst @@ -220,17 +220,14 @@ The default DB search backend uses Django's ``__icontains`` filter. Elasticsearch Backend ````````````````````` -Prerequisites are the Elasticsearch service itself and, via pip, the `elasticutils`_ and `pyelasticsearch`_ packages: +Prerequisites are the Elasticsearch service itself and, via pip, the `elasticsearch-py`_ package: .. code-block:: guess - pip install elasticutils==0.8.2 pyelasticsearch + pip install elasticsearch .. note:: - ElasticUtils 0.9+ is not supported. - -.. note:: - The dependency on elasticutils and pyelasticsearch is scheduled to be replaced by a dependency on `elasticsearch-py`_. + If you are using Elasticsearch < 1.0, install elasticsearch-py version 0.4.5: ```pip install elasticsearch==0.4.5``` The backend is configured in settings: @@ -246,7 +243,7 @@ The backend is configured in settings: } } -Other than ``BACKEND`` the keys are optional and default to the values shown. ``FORCE_NEW`` is used by elasticutils. In addition, any other keys are passed directly to the Elasticsearch constructor as case-sensitive keyword arguments (e.g. ``'max_retries': 1``). +Other than ``BACKEND`` the keys are optional and default to the values shown. ``FORCE_NEW`` is used by elasticsearch-py. In addition, any other keys are passed directly to the Elasticsearch constructor as case-sensitive keyword arguments (e.g. ``'max_retries': 1``). If you prefer not to run an Elasticsearch server in development or production, there are many hosted services available, including `Searchly`_, who offer a free account suitable for testing and development. To use Searchly: @@ -256,8 +253,6 @@ If you prefer not to run an Elasticsearch server in development or production, t - Configure ``URLS`` and ``INDEX`` in the Elasticsearch entry in ``WAGTAILSEARCH_BACKENDS`` - Run ``./manage.py update_index`` -.. _elasticutils: http://elasticutils.readthedocs.org -.. _pyelasticsearch: http://pyelasticsearch.readthedocs.org .. _elasticsearch-py: http://elasticsearch-py.readthedocs.org .. _Searchly: http://www.searchly.com/ .. _dashboard.searchly.com/users/sign\_up: https://dashboard.searchly.com/users/sign_up From 765657329e529f828e0bbf0185c162570301a539 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 23 Jun 2014 14:28:36 +0100 Subject: [PATCH 213/293] Changelog entry for #342 --- CHANGELOG.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e5cda8b44c4..ca58949b4b5 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -3,6 +3,7 @@ Changelog 0.4 (xx.xx.20xx) ~~~~~~~~~~~~~~~~ + * ElasticUtils/pyelasticsearch swapped for elasticsearch-py * Added 'original' as a resizing rule supported by the 'image' tag * Hallo.js updated to version 1.0.4 * Snippets are now ordered alphabetically From 64eed9684173c9e1be39883061d595de3bb2a69f Mon Sep 17 00:00:00 2001 From: Robert Clark Date: Mon, 23 Jun 2014 11:40:25 -0400 Subject: [PATCH 214/293] moved tests to page model instead of queryset --- wagtail/wagtailcore/tests/test_page_model.py | 22 +++++++++++++++++++ .../wagtailcore/tests/test_page_queryset.py | 18 --------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/wagtail/wagtailcore/tests/test_page_model.py b/wagtail/wagtailcore/tests/test_page_model.py index 1bae57952ce..dfc45d72a44 100644 --- a/wagtail/wagtailcore/tests/test_page_model.py +++ b/wagtail/wagtailcore/tests/test_page_model.py @@ -224,3 +224,25 @@ def test_move_page(self): christmas = events_index.get_children().get(slug='christmas') self.assertEqual(christmas.depth, 5) self.assertEqual(christmas.url_path, '/home/about-us/events/christmas/') + + +class TestPagePagination(TestCase): + fixtures = ['test.json'] + + def test_published_next(self): + events_index = Page.objects.get(url_path='/home/events/') + current_page = Page.objects.descendant_of(events_index).live().first() + + # All pages must be live + while current_page: + self.assertTrue(current_page.live) + current_page = current_page.get_next_siblings().live().first() + + def test_published_prev(self): + events_index = Page.objects.get(url_path='/home/events/') + current_page = Page.objects.descendant_of(events_index).live().last() + + # All pages must be live + while current_page: + self.assertTrue(current_page.live) + current_page = current_page.get_prev_siblings().live().first() diff --git a/wagtail/wagtailcore/tests/test_page_queryset.py b/wagtail/wagtailcore/tests/test_page_queryset.py index 020d98d153a..06f2c3e21c3 100644 --- a/wagtail/wagtailcore/tests/test_page_queryset.py +++ b/wagtail/wagtailcore/tests/test_page_queryset.py @@ -254,21 +254,3 @@ def test_not_type(self): # Check that the homepage is in the results homepage = Page.objects.get(url_path='/home/') self.assertTrue(pages.filter(id=homepage.id).exists()) - - def test_published_next(self): - events_index = Page.objects.get(url_path='/home/events/') - current_page = Page.objects.descendant_of(events_index).live().first() - - # All pages must be live - while current_page: - self.assertTrue(current_page.live) - current_page = current_page.get_next_siblings().live().first() - - def test_published_prev(self): - events_index = Page.objects.get(url_path='/home/events/') - current_page = Page.objects.descendant_of(events_index).live().last() - - # All pages must be live - while current_page: - self.assertTrue(current_page.live) - current_page = current_page.get_prev_siblings().live().first() From 66dce8df0349fe7bda8a838eed2d3791993ce627 Mon Sep 17 00:00:00 2001 From: Tim Heap Date: Tue, 24 Jun 2014 17:12:10 +1000 Subject: [PATCH 215/293] Make the 'X Pages/Images/Documents' stats links They link to the relevant sections of the admin, allowing for quick jumping around. --- .../static/wagtailadmin/scss/layouts/home.scss | 7 +++++++ .../templates/wagtailadmin/home/site_summary.html | 8 +++++++- wagtail/wagtailadmin/views/home.py | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/home.scss b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/home.scss index 40711ef7b30..f1e2ee77923 100644 --- a/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/home.scss +++ b/wagtail/wagtailadmin/static/wagtailadmin/scss/layouts/home.scss @@ -46,6 +46,13 @@ header{ } } + a{ + position:relative; + display:block; + width:100%; + height:100%; + } + span{ font-family:Bitter, Georgia, serif; display:block; diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/home/site_summary.html b/wagtail/wagtailadmin/templates/wagtailadmin/home/site_summary.html index 8a03b4e042e..225568fab32 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/home/site_summary.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/home/site_summary.html @@ -3,25 +3,31 @@

    {% trans "Site summary" %}

    - \ No newline at end of file + diff --git a/wagtail/wagtailadmin/views/home.py b/wagtail/wagtailadmin/views/home.py index 24800eefc74..77177b6522d 100644 --- a/wagtail/wagtailadmin/views/home.py +++ b/wagtail/wagtailadmin/views/home.py @@ -7,7 +7,7 @@ from wagtail.wagtailadmin import hooks from wagtail.wagtailadmin.forms import SearchForm -from wagtail.wagtailcore.models import Page, PageRevision, UserPagePermissionsProxy +from wagtail.wagtailcore.models import Site, Page, PageRevision, UserPagePermissionsProxy from wagtail.wagtaildocs.models import Document @@ -27,6 +27,7 @@ def render(self): 'total_pages': Page.objects.count() - 1, # subtract 1 because the root node is not a real page 'total_images': get_image_model().objects.count(), 'total_docs': Document.objects.count(), + 'root_page': Site.find_for_request(self.request).root_page, 'search_form': SearchForm(), }, RequestContext(self.request)) From d25b6fb6c05a60de7f474201d794fbfcf8fbe135 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 24 Jun 2014 09:12:08 +0100 Subject: [PATCH 216/293] Put prefetch_related back --- .../wagtailsearch/backends/elasticsearch.py | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/wagtail/wagtailsearch/backends/elasticsearch.py b/wagtail/wagtailsearch/backends/elasticsearch.py index 29141542a54..5561a3ceeac 100644 --- a/wagtail/wagtailsearch/backends/elasticsearch.py +++ b/wagtail/wagtailsearch/backends/elasticsearch.py @@ -13,7 +13,6 @@ from wagtail.wagtailsearch.indexed import Indexed - class ElasticSearchQuery(object): def __init__(self, model, query_string, fields=None, filters={}): self.model = model @@ -113,9 +112,10 @@ def __repr__(self): class ElasticSearchResults(object): - def __init__(self, backend, query): + def __init__(self, backend, query, prefetch_related=None): self.backend = backend self.query = query + self.prefetch_related = prefetch_related self.start = 0 self.stop = None self._results_cache = None @@ -136,7 +136,7 @@ def _set_limits(self, start=None, stop=None): def _clone(self): klass = self.__class__ - new = klass(self.backend, self.query) + new = klass(self.backend, self.query, prefetch_related=self.prefetch_related) new.start = self.start new.stop = self.stop return new @@ -167,8 +167,15 @@ def _do_search(self): # Initialise results dictionary results = dict((str(pk), None) for pk in pks) - # Find objects in database and add them to dict + # Get queryset queryset = self.query.model.objects.filter(pk__in=pks) + + # Add prefetch related + if self.prefetch_related: + for prefetch in self.prefetch_related: + queryset = queryset.prefetch_related(prefetch) + + # Find objects in database and add them to dict for obj in queryset: results[str(obj.pk)] = obj @@ -417,8 +424,5 @@ def search(self, query_string, model, fields=None, filters={}, prefetch_related= if not query_string: return [] - # Give deprecation warning if prefetch_related was used - warnings.warn("prefetch_related on search queries is no longer implemented. ", DeprecationWarning) - # Return search results - return ElasticSearchResults(self, ElasticSearchQuery(model, query_string, fields=fields, filters=filters)) + return ElasticSearchResults(self, ElasticSearchQuery(model, query_string, fields=fields, filters=filters), prefetch_related=prefetch_related) From 3c1883bca0d4e60e9b60213f01dc405b63948035 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 24 Jun 2014 09:42:31 +0100 Subject: [PATCH 217/293] Put prefetch related back in database backend --- wagtail/wagtailsearch/backends/db.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wagtail/wagtailsearch/backends/db.py b/wagtail/wagtailsearch/backends/db.py index 0531bc3aada..08fdaf048ce 100644 --- a/wagtail/wagtailsearch/backends/db.py +++ b/wagtail/wagtailsearch/backends/db.py @@ -66,7 +66,9 @@ def search(self, query_string, model, fields=None, filters={}, prefetch_related= # Distinct query = query.distinct() - # Give deprecation warning if prefetch_related was used - warnings.warn("prefetch_related on search queries is no longer implemented. ", DeprecationWarning) + # Prefetch related + if prefetch_related: + for prefetch in prefetch_related: + query = query.prefetch_related(prefetch) return query \ No newline at end of file From bdbcf3cd99d5b44ca275e38da5e6bab0ab181609 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 24 Jun 2014 09:53:41 +0100 Subject: [PATCH 218/293] Updated deprecation warning messages of moved template tags libraries --- wagtail/wagtailcore/templatetags/pageurl.py | 4 ++-- wagtail/wagtailcore/templatetags/rich_text.py | 4 ++-- wagtail/wagtailembeds/templatetags/embed_filters.py | 4 ++-- wagtail/wagtailimages/templatetags/image_tags.py | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/wagtail/wagtailcore/templatetags/pageurl.py b/wagtail/wagtailcore/templatetags/pageurl.py index fe64a302f6a..b31756c308b 100644 --- a/wagtail/wagtailcore/templatetags/pageurl.py +++ b/wagtail/wagtailcore/templatetags/pageurl.py @@ -1,8 +1,8 @@ import warnings warnings.warn( - "The pageurl tags has been renamed. " - "Use wagtailcore_tags instead.", DeprecationWarning) + "The pageurl tag library has been moved to wagtailcore_tags. " + "Use {% load wagtailcore_tags %} instead.", DeprecationWarning) from wagtail.wagtailcore.templatetags.wagtailcore_tags import register diff --git a/wagtail/wagtailcore/templatetags/rich_text.py b/wagtail/wagtailcore/templatetags/rich_text.py index 94c2d176c1e..ed8ac6f0f00 100644 --- a/wagtail/wagtailcore/templatetags/rich_text.py +++ b/wagtail/wagtailcore/templatetags/rich_text.py @@ -1,8 +1,8 @@ import warnings warnings.warn( - "The rich_text tags has been renamed. " - "Use wagtailcore_tags instead.", DeprecationWarning) + "The rich_text tag library has been moved to wagtailcore_tags. " + "Use {% load wagtailcore_tags %} instead.", DeprecationWarning) from wagtail.wagtailcore.templatetags.wagtailcore_tags import register diff --git a/wagtail/wagtailembeds/templatetags/embed_filters.py b/wagtail/wagtailembeds/templatetags/embed_filters.py index 25326fec607..7d3500e5815 100644 --- a/wagtail/wagtailembeds/templatetags/embed_filters.py +++ b/wagtail/wagtailembeds/templatetags/embed_filters.py @@ -1,8 +1,8 @@ import warnings warnings.warn( - "The embed_filters tags has been renamed. " - "Use wagtailembeds_tags instead.", DeprecationWarning) + "The embed_filters tag library has been moved to wagtailcore_tags. " + "Use {% load wagtailembeds_tags %} instead.", DeprecationWarning) from wagtail.wagtailembeds.templatetags.wagtailembeds_tags import register diff --git a/wagtail/wagtailimages/templatetags/image_tags.py b/wagtail/wagtailimages/templatetags/image_tags.py index 7eba192d463..9a96356c9a2 100644 --- a/wagtail/wagtailimages/templatetags/image_tags.py +++ b/wagtail/wagtailimages/templatetags/image_tags.py @@ -1,8 +1,8 @@ import warnings warnings.warn( - "The image_tags tags has been renamed. " - "Use wagtailimages_tags instead.", DeprecationWarning) + "The image_tags tag library has been moved to wagtailcore_tags. " + "Use {% load wagtailimages_tags %} instead.", DeprecationWarning) from wagtail.wagtailimages.templatetags.wagtailimages_tags import register From 1a986bab0d9cc324c73c37f6ce4639157e342b97 Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Tue, 24 Jun 2014 10:26:44 +0100 Subject: [PATCH 219/293] Add unit tests for rich_text.py --- wagtail/tests/fixtures/test.json | 18 ++ wagtail/wagtailcore/tests/test_rich_text.py | 262 ++++++++++++++++++++ wagtail/wagtailcore/tests/tests.py | 47 ++-- wagtail/wagtailembeds/format.py | 1 - 4 files changed, 303 insertions(+), 25 deletions(-) create mode 100644 wagtail/wagtailcore/tests/test_rich_text.py diff --git a/wagtail/tests/fixtures/test.json b/wagtail/tests/fixtures/test.json index 11b82d9f169..bd4807e07b8 100644 --- a/wagtail/tests/fixtures/test.json +++ b/wagtail/tests/fixtures/test.json @@ -418,5 +418,23 @@ "page": 8, "submit_time": "2014-01-01T12:00:00.000Z" } +}, +{ + "pk": 1, + "model": "wagtaildocs.Document", + "fields": { + "title": "test document", + "created_at": "2014-01-01T12:00:00.000Z" + } +}, +{ + "pk": 1, + "model": "wagtailimages.Image", + "fields": { + "title": "test image", + "created_at": "2014-01-01T12:00:00.000Z", + "width": 0, + "height": 0 + } } ] diff --git a/wagtail/wagtailcore/tests/test_rich_text.py b/wagtail/wagtailcore/tests/test_rich_text.py new file mode 100644 index 00000000000..9c98c6d3f09 --- /dev/null +++ b/wagtail/wagtailcore/tests/test_rich_text.py @@ -0,0 +1,262 @@ +from mock import patch + +from django.test import TestCase + +from wagtail.wagtailcore.rich_text import ( + ImageEmbedHandler, + MediaEmbedHandler, + PageLinkHandler, + DocumentLinkHandler, + DbWhitelister, + extract_attrs, + expand_db_html +) +from bs4 import BeautifulSoup + + +class TestImageEmbedHandler(TestCase): + fixtures = ['wagtail/tests/fixtures/test.json'] + + def test_get_db_attributes(self): + soup = BeautifulSoup( + 'foo' + ) + tag = soup.b + result = ImageEmbedHandler.get_db_attributes(tag) + self.assertEqual(result, + {'alt': 'test-alt', + 'id': 'test-id', + 'format': 'test-format'}) + + def test_expand_db_attributes_page_does_not_exist(self): + result = ImageEmbedHandler.expand_db_attributes( + {'id': 0}, + False + ) + self.assertEqual(result, '') + + @patch('wagtail.wagtailimages.models.Image') + @patch('django.core.files.File') + def test_expand_db_attributes_not_for_editor(self, mock_file, mock_image): + result = ImageEmbedHandler.expand_db_attributes( + {'id': 1, + 'alt': 'test-alt', + 'format': 'left'}, + False + ) + self.assertIn('foo
    ' + ) + tag = soup.b + result = MediaEmbedHandler.get_db_attributes(tag) + self.assertEqual(result, + {'url': 'test-url'}) + + @patch('wagtail.wagtailembeds.embeds.oembed') + def test_expand_db_attributes_for_editor(self, oembed): + oembed.return_value = { + 'title': 'test title', + 'author_name': 'test author name', + 'provider_name': 'test provider name', + 'type': 'test type', + 'thumbnail_url': 'test thumbnail url', + 'width': 'test width', + 'height': 'test height', + 'html': 'test html' + } + result = MediaEmbedHandler.expand_db_attributes( + {'url': 'http://www.youtube.com/watch/'}, + True + ) + self.assertIn('
    ', result) + self.assertIn('

    test title

    ', result) + self.assertIn('

    URL: http://www.youtube.com/watch/

    ', result) + self.assertIn('

    Provider: test provider name

    ', result) + self.assertIn('

    Author: test author name

    ', result) + self.assertIn('test title', result) + + @patch('wagtail.wagtailembeds.embeds.oembed') + def test_expand_db_attributes_not_for_editor(self, oembed): + oembed.return_value = { + 'title': 'test title', + 'author_name': 'test author name', + 'provider_name': 'test provider name', + 'type': 'test type', + 'thumbnail_url': 'test thumbnail url', + 'width': 'test width', + 'height': 'test height', + 'html': 'test html' + } + result = MediaEmbedHandler.expand_db_attributes( + {'url': 'http://www.youtube.com/watch/'}, + False + ) + self.assertIn('test html', result) + + +class TestPageLinkHandler(TestCase): + fixtures = ['wagtail/tests/fixtures/test.json'] + + def test_get_db_attributes(self): + soup = BeautifulSoup( + 'foo' + ) + tag = soup.a + result = PageLinkHandler.get_db_attributes(tag) + self.assertEqual(result, + {'id': 'test-id'}) + + def test_expand_db_attributes_page_does_not_exist(self): + result = PageLinkHandler.expand_db_attributes( + {'id': 0}, + False + ) + self.assertEqual(result, '') + + def test_expand_db_attributes_for_editor(self): + result = PageLinkHandler.expand_db_attributes( + {'id': 1}, + True + ) + self.assertEqual(result, + '') + + def test_expand_db_attributes_not_for_editor(self): + result = PageLinkHandler.expand_db_attributes( + {'id': 1}, + False + ) + self.assertEqual(result, '') + + +class TestDocumentLinkHandler(TestCase): + fixtures = ['wagtail/tests/fixtures/test.json'] + + def test_get_db_attributes(self): + soup = BeautifulSoup( + 'foo' + ) + tag = soup.a + result = DocumentLinkHandler.get_db_attributes(tag) + self.assertEqual(result, + {'id': 'test-id'}) + + def test_expand_db_attributes_document_does_not_exist(self): + result = DocumentLinkHandler.expand_db_attributes( + {'id': 0}, + False + ) + self.assertEqual(result, '') + + def test_expand_db_attributes_for_editor(self): + result = DocumentLinkHandler.expand_db_attributes( + {'id': 1}, + True + ) + self.assertEqual(result, + '') + + def test_expand_db_attributes_not_for_editor(self): + result = DocumentLinkHandler.expand_db_attributes( + {'id': 1}, + False + ) + self.assertEqual(result, + '') + + +class TestDbWhiteLister(TestCase): + def test_clean_tag_node_div(self): + soup = BeautifulSoup( + '
    foo
    ' + ) + tag = soup.div + self.assertEqual(tag.name, 'div') + DbWhitelister.clean_tag_node(soup, tag) + self.assertEqual(tag.name, 'p') + + def test_clean_tag_node_with_data_embedtype(self): + soup = BeautifulSoup( + '

    foo

    ' + ) + tag = soup.p + DbWhitelister.clean_tag_node(soup, tag) + self.assertEqual(str(tag), + '

    ') + + def test_clean_tag_node_with_data_linktype(self): + soup = BeautifulSoup( + 'foo' + ) + tag = soup.a + DbWhitelister.clean_tag_node(soup, tag) + self.assertEqual(str(tag), 'foo') + + def test_clean_tag_node(self): + soup = BeautifulSoup( + 'foo' + ) + tag = soup.a + DbWhitelister.clean_tag_node(soup, tag) + self.assertEqual(str(tag), 'foo') + + +class TestExtractAttrs(TestCase): + def test_extract_attr(self): + html = 'snowman' + result = extract_attrs(html) + self.assertEqual(result, {'foo': 'bar', 'baz': 'quux'}) + + +class TestExpandDbHtml(TestCase): + def test_expand_db_html_with_linktype(self): + html = 'foo' + result = expand_db_html(html) + self.assertEqual(result, 'foo') + + def test_expand_db_html_no_linktype(self): + html = 'foo' + result = expand_db_html(html) + self.assertEqual(result, 'foo') + + @patch('wagtail.wagtailembeds.embeds.oembed') + def test_expand_db_html_with_embed(self, oembed): + oembed.return_value = { + 'title': 'test title', + 'author_name': 'test author name', + 'provider_name': 'test provider name', + 'type': 'test type', + 'thumbnail_url': 'test thumbnail url', + 'width': 'test width', + 'height': 'test height', + 'html': 'test html' + } + html = '' + result = expand_db_html(html) + self.assertIn('test html', result) diff --git a/wagtail/wagtailcore/tests/tests.py b/wagtail/wagtailcore/tests/tests.py index d10474bbaf9..d7d9a24f97c 100644 --- a/wagtail/wagtailcore/tests/tests.py +++ b/wagtail/wagtailcore/tests/tests.py @@ -1,12 +1,7 @@ -from StringIO import StringIO +from django.test import TestCase -from django.test import TestCase, Client -from django.http import HttpRequest, Http404 -from django.core import management -from django.contrib.auth.models import User - -from wagtail.wagtailcore.models import Page, Site, UserPagePermissionsProxy -from wagtail.tests.models import EventPage, EventIndex, SimplePage +from wagtail.wagtailcore.models import Page, Site +from wagtail.tests.models import SimplePage class TestPageUrlTags(TestCase): @@ -15,25 +10,28 @@ class TestPageUrlTags(TestCase): def test_pageurl_tag(self): response = self.client.get('/events/') self.assertEqual(response.status_code, 200) - self.assertContains(response, 'Christmas') + self.assertContains(response, + 'Christmas') def test_slugurl_tag(self): response = self.client.get('/events/christmas/') self.assertEqual(response.status_code, 200) - self.assertContains(response, 'Back to events index') + self.assertContains(response, + 'Back to events index') class TestIssue7(TestCase): """ - This tests for an issue where if a site root page was moved, all the page - urls in that site would change to None. + This tests for an issue where if a site root page was moved, all + the page urls in that site would change to None. - The issue was caused by the 'wagtail_site_root_paths' cache variable not being - cleared when a site root page was moved. Which left all the child pages - thinking that they are no longer in the site and return None as their url. + The issue was caused by the 'wagtail_site_root_paths' cache + variable not being cleared when a site root page was moved. Which + left all the child pages thinking that they are no longer in the + site and return None as their url. - Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682 - Discussion: https://github.com/torchbox/wagtail/issues/7 + Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682 Discussion: + https://github.com/torchbox/wagtail/issues/7 """ fixtures = ['test.json'] @@ -67,15 +65,16 @@ def test_issue7(self): class TestIssue157(TestCase): """ - This tests for an issue where if a site root pages slug was changed, all the page - urls in that site would change to None. + This tests for an issue where if a site root pages slug was + changed, all the page urls in that site would change to None. - The issue was caused by the 'wagtail_site_root_paths' cache variable not being - cleared when a site root page was changed. Which left all the child pages - thinking that they are no longer in the site and return None as their url. + The issue was caused by the 'wagtail_site_root_paths' cache + variable not being cleared when a site root page was changed. + Which left all the child pages thinking that they are no longer in + the site and return None as their url. - Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682 - Discussion: https://github.com/torchbox/wagtail/issues/157 + Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682 Discussion: + https://github.com/torchbox/wagtail/issues/157 """ fixtures = ['test.json'] diff --git a/wagtail/wagtailembeds/format.py b/wagtail/wagtailembeds/format.py index 1654be989e8..8a73ff52429 100644 --- a/wagtail/wagtailembeds/format.py +++ b/wagtail/wagtailembeds/format.py @@ -1,6 +1,5 @@ from __future__ import division # Use true division -from django.utils.html import escape from django.template.loader import render_to_string from wagtail.wagtailembeds import get_embed From b41a6d730fe61e1c5e01d9b669403982f374f4ad Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 24 Jun 2014 12:53:34 +0100 Subject: [PATCH 220/293] Revert "Merge pull request #335 from mope/edit-handlers-unit-tests" This reverts commit 7ad6be82f3913893dcd82dd2af904da4c654c3ff, reversing changes made to 4c77a4b18a8fef9abd3bcc1fccaf5627f1604522. --- .gitignore | 1 - wagtail/wagtailadmin/edit_handlers.py | 39 +- .../wagtailadmin/tests/test_edit_handlers.py | 481 ------------------ 3 files changed, 18 insertions(+), 503 deletions(-) delete mode 100644 wagtail/wagtailadmin/tests/test_edit_handlers.py diff --git a/.gitignore b/.gitignore index 57f9d0eab5e..bd904efc9d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.pyc .DS_Store -/.ropeproject/ /.coverage /dist/ /MANIFEST diff --git a/wagtail/wagtailadmin/edit_handlers.py b/wagtail/wagtailadmin/edit_handlers.py index 7bbead9b19b..a15440016ce 100644 --- a/wagtail/wagtailadmin/edit_handlers.py +++ b/wagtail/wagtailadmin/edit_handlers.py @@ -1,4 +1,6 @@ import copy +import re +import datetime from taggit.forms import TagWidget from modelcluster.forms import ClusterForm, ClusterFormMetaclass @@ -7,13 +9,13 @@ from django.template.defaultfilters import addslashes from django.utils.safestring import mark_safe from django import forms +from django.db import models from django.forms.models import fields_for_model from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ( - ObjectDoesNotExist, - ImproperlyConfigured, -) +from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured, ValidationError from django.core.urlresolvers import reverse +from django.conf import settings +from django.utils.translation import ugettext as _ from django.utils.translation import ugettext_lazy from wagtail.wagtailcore.models import Page @@ -36,8 +38,7 @@ } -# Callback to allow us to override the default form fields provided -# for each model field. +# Callback to allow us to override the default form fields provided for each model field. def formfield_for_dbfield(db_field, **kwargs): # snarfed from django/contrib/admin/options.py @@ -55,13 +56,13 @@ def formfield_for_dbfield(db_field, **kwargs): class WagtailAdminModelFormMetaclass(ClusterFormMetaclass): # Override the behaviour of the regular ModelForm metaclass - # which handles the translation of model fields to form fields - - # to use our own formfield_for_dbfield function to do that - # translation. This is done by sneaking a formfield_callback - # property into the class being defined (unless the class already - # provides a formfield_callback of its own). + # to use our own formfield_for_dbfield function to do that translation. + # This is done by sneaking a formfield_callback property into the class + # being defined (unless the class already provides a formfield_callback + # of its own). - # while we're at it, we'll also set extra_form_count to 0, as - # we're creating extra forms in JS + # while we're at it, we'll also set extra_form_count to 0, as we're creating + # extra forms in JS extra_form_count = 0 def __new__(cls, name, bases, attrs): @@ -78,8 +79,8 @@ def __new__(cls, name, bases, attrs): def get_form_for_model( - model, fields=None, exclude=None, formsets=None, - exclude_formsets=None, widgets=None + model, + fields=None, exclude=None, formsets=None, exclude_formsets=None, widgets=None ): # django's modelform_factory with a bit of custom behaviour @@ -93,8 +94,7 @@ def get_form_for_model( if exclude is not None: attrs['exclude'] = exclude if issubclass(model, Page): - attrs['exclude'] = attrs.get('exclude', []) + ['content_type', 'path', - 'depth', 'numchild'] + attrs['exclude'] = attrs.get('exclude', []) + ['content_type', 'path', 'depth', 'numchild'] if widgets is not None: attrs['widgets'] = widgets @@ -111,9 +111,7 @@ def get_form_for_model( 'Meta': type('Meta', (object,), attrs) } - return WagtailAdminModelFormMetaclass(class_name, - (WagtailAdminModelForm,), - form_class_attrs) + return WagtailAdminModelFormMetaclass(class_name, (WagtailAdminModelForm,), form_class_attrs) def extract_panel_definitions_from_model_class(model, exclude=None): @@ -128,8 +126,7 @@ def extract_panel_definitions_from_model_class(model, exclude=None): if issubclass(model, Page): _exclude = ['content_type', 'path', 'depth', 'numchild'] - fields = fields_for_model(model, exclude=_exclude, - formfield_callback=formfield_for_dbfield) + fields = fields_for_model(model, exclude=_exclude, formfield_callback=formfield_for_dbfield) for field_name, field in fields.items(): try: diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py deleted file mode 100644 index c930974fefa..00000000000 --- a/wagtail/wagtailadmin/tests/test_edit_handlers.py +++ /dev/null @@ -1,481 +0,0 @@ -from mock import MagicMock - -from django.test import TestCase -from django.core.exceptions import ImproperlyConfigured -from django.forms.widgets import HiddenInput - -from wagtail.wagtailadmin.edit_handlers import ( - get_form_for_model, - extract_panel_definitions_from_model_class, - BaseFieldPanel, - FieldPanel, - RichTextFieldPanel, - EditHandler, - WagtailAdminModelForm, - BaseTabbedInterface, - TabbedInterface, - BaseObjectList, - ObjectList, - PageChooserPanel, - InlinePanel -) -from wagtail.wagtailcore.models import Page, Site - - -class TestGetFormForModel(TestCase): - class FakeClass(object): - _meta = MagicMock() - - def setUp(self): - self.mock_exclude = MagicMock() - - def test_get_form_for_model(self): - form = get_form_for_model(self.FakeClass, - fields=[], - exclude=[self.mock_exclude], - formsets=['baz'], - exclude_formsets=['quux'], - widgets=['bacon']) - self.assertEqual(form.Meta.exclude, [self.mock_exclude]) - self.assertEqual(form.Meta.formsets, ['baz']) - self.assertEqual(form.Meta.exclude_formsets, ['quux']) - self.assertEqual(form.Meta.widgets, ['bacon']) - - -class TestExtractPanelDefinitionsFromModelClass(TestCase): - class FakePage(Page): - pass - - def test_can_extract_panels(self): - mock = MagicMock() - mock.panels = 'foo' - result = extract_panel_definitions_from_model_class(mock) - self.assertEqual(result, 'foo') - - def test_exclude(self): - panels = extract_panel_definitions_from_model_class(Site, exclude=['hostname']) - for panel in panels: - self.assertNotEqual(panel.field_name, 'hostname') - - def test_extracted_objects_are_panels(self): - panels = extract_panel_definitions_from_model_class(self.FakePage) - for panel in panels: - self.assertTrue(issubclass(panel, BaseFieldPanel)) - - -class TestEditHandler(TestCase): - class FakeForm(dict): - def __init__(self, *args, **kwargs): - self.fields = self.fields_iterator() - - def fields_iterator(self): - for i in self: - yield i - - def setUp(self): - self.edit_handler = EditHandler(form=True, instance=True) - self.edit_handler.render = lambda: "foo" - - def test_widget_overrides(self): - result = EditHandler.widget_overrides() - self.assertEqual(result, {}) - - def test_required_formsets(self): - result = EditHandler.required_formsets() - self.assertEqual(result, []) - - def test_get_form_class(self): - result = EditHandler.get_form_class(Page) - self.assertTrue(issubclass(result, WagtailAdminModelForm)) - - def test_edit_handler_init_no_instance(self): - self.assertRaises(ValueError, EditHandler, form=True) - - def test_edit_handler_init_no_form(self): - self.assertRaises(ValueError, EditHandler, instance=True) - - def test_object_classnames(self): - result = self.edit_handler.object_classnames() - self.assertEqual(result, "") - - def test_field_classnames(self): - result = self.edit_handler.field_classnames() - self.assertEqual(result, "") - - def test_field_type(self): - result = self.edit_handler.field_type() - self.assertEqual(result, "") - - def test_render_as_object(self): - result = self.edit_handler.render_as_object() - self.assertEqual(result, "foo") - - def test_render_as_field(self): - result = self.edit_handler.render_as_field() - self.assertEqual(result, "foo") - - def test_render_js(self): - result = self.edit_handler.render_js() - self.assertEqual(result, "") - - def test_rendered_fields(self): - result = self.edit_handler.rendered_fields() - self.assertEqual(result, []) - - def test_render_missing_fields(self): - fake_form = self.FakeForm() - fake_form["foo"] = "bar" - self.edit_handler.form = fake_form - self.assertEqual(self.edit_handler.render_missing_fields(), "bar") - - def test_render_form_content(self): - fake_form = self.FakeForm() - fake_form["foo"] = "bar" - self.edit_handler.form = fake_form - self.assertEqual(self.edit_handler.render_form_content(), "foobar") - - -class TestTabbedInterface(TestCase): - class FakeChild(object): - class FakeGrandchild(object): - def render_js(self): - return "rendered js" - - def rendered_fields(self): - return ["rendered fields"] - - def widget_overrides(self): - return {'foo': 'bar'} - - def required_formsets(self): - return {'baz': 'quux'} - - def __call__(self, *args, **kwargs): - fake_grandchild = self.FakeGrandchild() - return fake_grandchild - - def setUp(self): - fake_child = self.FakeChild() - self.TabbedInterfaceClass = TabbedInterface([fake_child]) - self.tabbed_interface = self.TabbedInterfaceClass(instance=True, - form=True) - - def test_tabbed_interface(self): - self.assertTrue(issubclass(self.TabbedInterfaceClass, - BaseTabbedInterface)) - - def test_object_classnames_no_classname(self): - result = self.tabbed_interface.object_classnames() - self.assertEqual(result, 'multi-field') - - def test_object_classnames(self): - self.tabbed_interface.classname = 'foo' - result = self.tabbed_interface.object_classnames() - self.assertEqual(result, 'multi-field foo') - - def test_widget_overrides(self): - result = self.tabbed_interface.widget_overrides() - self.assertEqual(result, {'foo': 'bar'}) - - def test_required_formsets(self): - result = self.tabbed_interface.required_formsets() - self.assertEqual(result, ['baz']) - - def test_render(self): - result = self.tabbed_interface.render() - self.assertIn('
    ', result) - - def test_render_js(self): - result = self.tabbed_interface.render_js() - self.assertEqual(result, 'rendered js') - - def test_rendered_fields(self): - result = self.tabbed_interface.rendered_fields() - self.assertEqual(result, ["rendered fields"]) - - -class TestObjectList(TestCase): - def test_object_list(self): - object_list = ObjectList(['foo']) - self.assertTrue(issubclass(object_list, BaseObjectList)) - - -class TestBaseFieldPanel(TestCase): - class FakeClass(object): - required = False - - class FakeField(object): - label = 'label' - help_text = 'help text' - - def setUp(self): - fake_field = self.FakeField() - BaseFieldPanel.field_name = 'barbecue' - self.base_field_panel = BaseFieldPanel( - instance=True, - form={'barbecue': fake_field}) - - def test_object_classnames_no_classname(self): - result = self.base_field_panel.object_classnames() - self.assertEqual(result, "single-field") - - def test_object_classnames(self): - self.base_field_panel.classname = "bar" - result = self.base_field_panel.object_classnames() - self.assertEqual(result, "single-field bar") - - def test_field_type(self): - fake_object = self.FakeClass() - another_fake_object = self.FakeClass() - fake_object.field = another_fake_object - self.base_field_panel.bound_field = fake_object - self.assertEqual(self.base_field_panel.field_type(), 'fake_class') - - def test_field_classnames(self): - fake_object = self.FakeClass() - another_fake_object = self.FakeClass() - another_fake_object.required = True - fake_object.errors = True - fake_object.field = another_fake_object - self.base_field_panel.bound_field = fake_object - self.assertEqual(self.base_field_panel.field_classnames(), - 'fake_class required error') - - -class TestFieldPanel(TestCase): - class FakeClass(object): - required = False - - class FakeField(object): - label = 'label' - help_text = 'help text' - errors = ['errors'] - id_for_label = 'id for label' - - def setUp(self): - fake_field = self.FakeField() - fake_field.field = self.FakeClass() - self.field_panel = FieldPanel('barbecue', 'snowman')( - instance=True, - form={'barbecue': fake_field}) - - def test_render_as_object(self): - result = self.field_panel.render_as_object() - self.assertIn('label', - result) - self.assertIn('
  • ', - result) - self.assertIn('

    ', - result) - - def test_render_js_unknown_widget(self): - field = self.FakeField() - bound_field = self.FakeField() - widget = self.FakeField() - field.widget = widget - bound_field.field = field - self.field_panel.bound_field = bound_field - result = self.field_panel.render_js() - self.assertEqual(result, - '') - - def test_render_as_field(self): - field = self.FakeField() - bound_field = self.FakeField() - bound_field.field = field - self.field_panel.bound_field = bound_field - result = self.field_panel.render_as_field() - self.assertIn('

    help text

    ', - result) - self.assertIn('errors', - result) - - def test_rendered_fields(self): - result = self.field_panel.rendered_fields() - self.assertEqual(result, ['barbecue']) - - -class TestRichTextFieldPanel(TestCase): - class FakeField(object): - label = 'label' - help_text = 'help text' - errors = ['errors'] - id_for_label = 'id for label' - - def test_render_js(self): - fake_field = self.FakeField() - rich_text_field_panel = RichTextFieldPanel('barbecue')( - instance=True, - form={'barbecue': fake_field}) - result = rich_text_field_panel.render_js() - self.assertEqual(result, - "makeRichTextEditable(fixPrefix('id for label'));") - - -class TestPageChooserPanel(TestCase): - class FakeField(object): - label = 'label' - help_text = 'help text' - errors = ['errors'] - id_for_label = 'id for label' - - class FakeInstance(object): - class FakePage(object): - class FakeParent(object): - id = 1 - - name = 'fake page' - - def get_parent(self): - return self.FakeParent() - - def __init__(self): - fake_page = self.FakePage() - self.barbecue = fake_page - - def setUp(self): - fake_field = self.FakeField() - fake_instance = self.FakeInstance() - self.page_chooser_panel = PageChooserPanel('barbecue')( - instance=fake_instance, - form={'barbecue': fake_field}) - - def test_render_js(self): - result = self.page_chooser_panel.render_js() - self.assertEqual(result, - "createPageChooser(fixPrefix('id for label'), 'wagtailcore.page', 1);") - - def test_get_chosen_item(self): - result = self.page_chooser_panel.get_chosen_item() - self.assertEqual(result.name, 'fake page') - - def test_render_as_field(self): - result = self.page_chooser_panel.render_as_field() - self.assertIn('

    help text

    ', result) - self.assertIn('errors', result) - - def test_widget_overrides(self): - result = self.page_chooser_panel.widget_overrides() - self.assertEqual(result, {'barbecue': HiddenInput}) - - def test_target_content_type(self): - result = PageChooserPanel( - 'barbecue', - 'wagtailcore.site' - ).target_content_type() - self.assertEqual(result.name, 'site') - - def test_target_content_type_malformed_type(self): - result = PageChooserPanel( - 'barbecue', - 'snowman' - ) - self.assertRaises(ImproperlyConfigured, - result.target_content_type) - - def test_target_content_type_nonexistent_type(self): - result = PageChooserPanel( - 'barbecue', - 'snowman.lorry' - ) - self.assertRaises(ImproperlyConfigured, - result.target_content_type) - - -class TestInlinePanel(TestCase): - class FakeField(object): - class FakeFormset(object): - class FakeForm(object): - class FakeInstance(object): - def __repr__(self): - return 'fake instance' - fields = {'DELETE': MagicMock(), - 'ORDER': MagicMock()} - instance = FakeInstance() - - def __repr__(self): - return 'fake form' - - forms = [FakeForm()] - empty_form = FakeForm() - can_order = True - - label = 'label' - help_text = 'help text' - errors = ['errors'] - id_for_label = 'id for label' - formsets = {'formset': FakeFormset()} - - class FakeInstance(object): - class FakePage(object): - class FakeParent(object): - id = 1 - - name = 'fake page' - - def get_parent(self): - return self.FakeParent() - - def __init__(self): - fake_page = self.FakePage() - self.barbecue = fake_page - - def setUp(self): - self.fake_field = self.FakeField() - self.fake_instance = self.FakeInstance() - self.mock_panel = MagicMock() - self.mock_panel.name = 'mock panel' - self.mock_model = MagicMock() - self.mock_model.formset.related.model.panels = [self.mock_panel] - - def test_get_panel_definitions_no_panels(self): - """ - Check that get_panel_definitions returns the panels set on the model - when no panels are set on the InlinePanel - """ - inline_panel = InlinePanel(self.mock_model, 'formset')( - instance=self.fake_instance, - form=self.fake_field) - result = inline_panel.get_panel_definitions() - self.assertEqual(result[0].name, 'mock panel') - expected_calls = '[call(instance=fake instance, form=fake form),\n call(instance=fake instance, form=fake form)]' - self.assertEqual(str(self.mock_panel.mock_calls), expected_calls) - - def test_get_panel_definitions(self): - """ - Check that get_panel_definitions returns the panels set on - InlinePanel - """ - other_mock_panel = MagicMock() - other_mock_panel.name = 'other mock panel' - inline_panel = InlinePanel(self.mock_model, - 'formset', - panels=[other_mock_panel])( - instance=self.fake_instance, - form=self.fake_field) - result = inline_panel.get_panel_definitions() - self.assertEqual(result[0].name, 'other mock panel') - expected_calls = '[call(instance=fake instance, form=fake form),\n call(instance=fake instance, form=fake form)]' - self.assertEqual(str(other_mock_panel.mock_calls), expected_calls) - - def test_required_formsets(self): - inline_panel = InlinePanel(self.mock_model, 'formset')( - instance=self.fake_instance, - form=self.fake_field) - self.assertEqual(inline_panel.required_formsets(), ['formset']) - - def test_render(self): - inline_panel = InlinePanel(self.mock_model, - 'formset', - label='foo')( - instance=self.fake_instance, - form=self.fake_field) - self.assertIn('Add foo', inline_panel.render()) - - def test_render_js(self): - inline_panel = InlinePanel(self.mock_model, - 'formset')( - instance=self.fake_instance, - form=self.fake_field) - self.assertIn('var panel = InlinePanel({', - inline_panel.render_js()) From ea14d99d18918353d72613b0e55b8f542d88cd82 Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Tue, 24 Jun 2014 14:56:40 +0100 Subject: [PATCH 221/293] Alter comment formatting in wagtailcore tests.py --- wagtail/wagtailcore/tests/tests.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wagtail/wagtailcore/tests/tests.py b/wagtail/wagtailcore/tests/tests.py index d7d9a24f97c..5fd5aa8025e 100644 --- a/wagtail/wagtailcore/tests/tests.py +++ b/wagtail/wagtailcore/tests/tests.py @@ -30,8 +30,8 @@ class TestIssue7(TestCase): left all the child pages thinking that they are no longer in the site and return None as their url. - Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682 Discussion: - https://github.com/torchbox/wagtail/issues/7 + Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682 + Discussion: https://github.com/torchbox/wagtail/issues/7 """ fixtures = ['test.json'] @@ -73,8 +73,8 @@ class TestIssue157(TestCase): Which left all the child pages thinking that they are no longer in the site and return None as their url. - Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682 Discussion: - https://github.com/torchbox/wagtail/issues/157 + Fix: d6cce69a397d08d5ee81a8cbc1977ab2c9db2682 + Discussion: https://github.com/torchbox/wagtail/issues/157 """ fixtures = ['test.json'] From 1f645a7ba092c0fbd757ea5e9d2cfcd0b233bb87 Mon Sep 17 00:00:00 2001 From: Tom Talbot Date: Tue, 24 Jun 2014 15:38:13 +0100 Subject: [PATCH 222/293] Fix #80 Searching for a non-existent editor's pick now displays the correct not found message. --- wagtail/wagtailsearch/views/editorspicks.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wagtail/wagtailsearch/views/editorspicks.py b/wagtail/wagtailsearch/views/editorspicks.py index bb39c02baed..8e1155922a8 100644 --- a/wagtail/wagtailsearch/views/editorspicks.py +++ b/wagtail/wagtailsearch/views/editorspicks.py @@ -13,6 +13,7 @@ @permission_required('wagtailadmin.access_admin') @vary_on_headers('X-Requested-With') def index(request): + is_searching = False page = request.GET.get('p', 1) query_string = request.GET.get('q', "") @@ -21,6 +22,7 @@ def index(request): # Search if query_string: queries = queries.filter(query_string__icontains=query_string) + is_searching = True # Pagination paginator = Paginator(queries, 20) @@ -33,11 +35,13 @@ def index(request): if request.is_ajax(): return render(request, "wagtailsearch/editorspicks/results.html", { + 'is_searching': is_searching, 'queries': queries, 'query_string': query_string, }) else: return render(request, 'wagtailsearch/editorspicks/index.html', { + 'is_searching': is_searching, 'queries': queries, 'query_string': query_string, 'search_form': SearchForm(data=dict(q=query_string) if query_string else None, placeholder=_("Search editor's picks")), From 8cc4bdf39efbf5fb70b8daa9b148c88edc630aa6 Mon Sep 17 00:00:00 2001 From: Tim Heap Date: Wed, 25 Jun 2014 08:47:48 +1000 Subject: [PATCH 223/293] Link to the root page, not the site root --- .../wagtailadmin/templates/wagtailadmin/home/site_summary.html | 2 +- wagtail/wagtailadmin/views/home.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/home/site_summary.html b/wagtail/wagtailadmin/templates/wagtailadmin/home/site_summary.html index 225568fab32..166c0c91291 100644 --- a/wagtail/wagtailadmin/templates/wagtailadmin/home/site_summary.html +++ b/wagtail/wagtailadmin/templates/wagtailadmin/home/site_summary.html @@ -3,7 +3,7 @@

    {% trans "Site summary" %}

  • + +
    +
    + + +
    + +
    +